Rebuilt on top of REGL.

This commit is contained in:
Rezmason
2020-01-19 16:03:53 -08:00
parent 09677e5aa4
commit a760d6854a
22 changed files with 10869 additions and 49444 deletions

View File

@@ -19,7 +19,7 @@
---
### about
This project is a WebGL implementation of the raining green code seen in _The Matrix Trilogy_. It's currently dependent on [Three.js](https://github.com/mrdoob/three.js), though this may not be permanent.
This project is a WebGL implementation of the raining green code seen in _The Matrix Trilogy_. It's currently built on top of the functional WebGL wrapper, [REGL](http://regl.party); its previous Three.js version is maintained in a separate branch.
---
### goals
@@ -32,15 +32,16 @@ The way I see it, there's four kinds of Matrix effects people call ["digital rai
While there have been a lot of attempts at #1 and #3, they're all missing important parts of #4 that make digital rain so iconic. Here are the requirements for my implementation:
- **Get the right glyphs**. Like the actual ones. Everyone knows Matrix glyphs are some treatment of [Katakana](https://en.wikipedia.org/wiki/Katakana), but they're also a few characters from [Susan Kare's Chicago typeface](https://en.wikipedia.org/wiki/Chicago_(typeface)). The Matrix glyphs in *this* project come from the source: cleaned up vectors [from an old SWF](https://web.archive.org/web/20070914173039/http://www.atari.com:80/thematrixpathofneo/) for an official Matrix product, archived back in 2007. That's how deep this rabbit hole goes, friends.
- **Get the right glyphs**. Like the actual ones. Everyone knows Matrix glyphs are some treatment of [Katakana](https://en.wikipedia.org/wiki/Katakana), but they also include a few characters from [Susan Kare's Chicago typeface](https://en.wikipedia.org/wiki/Chicago_(typeface)). The Matrix glyphs in *this* project come from the source: cleaned up vectors [from an old SWF](https://web.archive.org/web/20070914173039/http://www.atari.com:80/thematrixpathofneo/) for an official Matrix product, archived back in 2007. That's how deep this rabbit hole goes, friends.
(Please support the [Internet Archive!](https://archive.org/about/))
- **Make it look sweet in 2D**. This is not a cop-out. There is just no scene in the movies as iconic as the digital rain itself, and while depth effects are cool, they take away from these other details that make the difference between a goodtrix and a *greatrix*.
- **The glyphs are in a *fixed grid* and *don't move*.** The "raindrops" we see in the 2D effect are changes in the brightness of symbols that occupy a column. To get a closer look at this, try setting the `fallSpeed` to a number close to 0.
- **Get the glow and color right.** Matrix symbols aren't just some shade of phosphorous green; they're first given a bloom effect, and then get tone-mapped to the green color palette.
- **Symbols change shape faster as they dim.** When symbols light up, they almost never change shape, but their cycle speed increases the darker and darker they get.
- **Two "raindrops" can occupy the same column.** This is complicated, because we can't allow them to collide.
- **Two "raindrops" can occupy the same column.** This is complicated, because we can't allow them to collide. A useful approach to thinking about this is, each column's glyph brightness is a kind of [sawtooth wave](http://mathworld.wolfram.com/SawtoothWave.html).
- **Capture the glyph sequence.** Yes, the symbols in the sequels' opening titles, which are arguably the highest quality versions of the 2D effect, change according to a repeating sequence (see `glyph order.txt`).
- **Make it free, open source and web based.** Because someone could probably improve on what I've done, and I'd like to see that, and maybe incorporate their improvements back into this project.
- **Support as many browsers and devices as possible.** This project used to rely on Three.js's GPUComputationRenderer, which only worked in browsers supporting WebGL's [oes_texture_float extension](https://caniuse.com/#search=OES_texture_float). The rewrite dropped this dependency, and gained support for a broader range of browsers and devices.
- **Whip up some artistic license and depict the *previous* Matrix versions.** The sequels describe [a paradisiacal predecessor](https://rezmason.github.io/matrix?version=paradise) to the Matrix that was too idyllic, [and another earlier, nightmarish Hobbesian version](https://rezmason.github.io/matrix?version=nightmare) that proved too campy. They depict some programs running older, differently colored code, so it's time someone tried rendering them.
- **Include the following statement in the README.md:** Sure, you can enjoy movies, including *The Matrix*, without reading too deeply into them, but if you're going to really think about a film, make it this one. And here's the thing: **The Matrix is a story about transitioning, directed by two siblings who transitioned**. So there! There's plenty more themes in it and its sequels than that, and plenty of room for interpretation, but no room for the misogynistic ideas that led to that gross subreddit we all know about. Wake up from your prejudices, boys. Here's a chance to open our minds, not shut them.
@@ -55,9 +56,9 @@ Now you know link fu. Here's a list of customization options:
- **version** - the version of the Matrix to simulate. Can be "paradise", "nightmare", "operator" or "classic" (default).
- "classic" is the Matrix code everyone knows and loves, mostly based on the sequels' opening title graphics.
- "operator" is more reminiscent of the matrix code as it appears in the first movie's opening titles, and on operators' screens: flatter, crowded, without a gradient, and with occasional effects (such as a square ripple).
- "paradise" is how the Matrix's idyllic predecessor may have appeared: warm, simplistic, encompassing.
- "nightmare" is how the Matrix may have appeared in the Merovingian's heyday: flashy, foreboding, relentless.
- "operator" is more reminiscent of the matrix code as it appears in the first movie's opening titles, and on operators' screens: flatter, crowded, without a gradient, and with occasional effects (such as a square ripple).
- **width** - the number of columns (and rows) to draw. Default is 80.
- **slant** - which angle is up, in degrees. Default is 0.
- **bloomSize** - The glow quality, from 0 to 1. Default is 0.5. Lowering this value may help the digital rain run smoother on your device.

View File

@@ -1,6 +1,6 @@
TODO:
Reach out to Ashley's partner about producing sounds
Reach out to someone about producing sounds
Raindrop sound
https://youtu.be/bPhu01wpf0k?t=34
https://youtu.be/Yt2-h13XK7Y?t=33
@@ -14,19 +14,11 @@ Reach out to Ashley's partner about producing sounds
https://youtu.be/gZzTVJ-NLYQ?t=230
And some kind of ambient sound that they play over
Why's it look different on Mobile Safari?
Much later:
Deluxe compute variables
Flashing row effect
Square event
Expanding white outline of a box
Delay it like the raindrop particles
Neo flying
Staticky julia set looking silhouette
Simpler bloom replacement?
More patterns?
Symbol duplication is common

View File

@@ -1,318 +1,100 @@
<html>
<head>
<title>Matrix digital rain</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
</head>
<body style="height: 100vh; margin: 0; overflow: hidden; position: fixed; padding: 0; width: 100vw;">
<script src="./lib/three.js"></script>
<script src="./js/CopyShader.js"></script>
<script src="./js/EffectComposer.js"></script>
<script src="./js/RenderPass.js"></script>
<script src="./js/ShaderPass.js"></script>
<script src="./js/ColorMapPass.js"></script>
<script src="./js/HorizontalColorationPass.js"></script>
<script src="./js/LuminosityHighPassShader.js"></script>
<script src="./js/UnrealBloomPass.js"></script>
<script src="./js/ImageOverlayPass.js"></script>
<script src="./js/GPUComputationRenderer.js"></script>
<script src="./js/MatrixRenderer.js"></script>
<script>
// iOS STOP SCROLLING DAMN IT
document.addEventListener('touchmove', e => e.preventDefault(), { passive: false });
const fonts = {
coptic: {
textureURL: "./coptic_msdf.png",
sequenceLength: 32
},
gothic: {
textureURL: "./gothic_msdf.png",
sequenceLength: 27
},
matrixcode: {
textureURL: "./matrixcode_msdf.png",
sequenceLength: 57
},
};
const versions = {
paradise: {
bloom: {
radius: 1.15,
strength: 3.5,
threshold: 0
},
cycleSpeed: 0.05,
cycleStyle: "cycleFasterWhenDimmed",
cursorEffectThreshold: 1,
brightnessOffset: 0.0,
brightnessMultiplier: 1.0,
fallSpeed: 0.05,
font: fonts.coptic,
glyphEdgeCrop: 0.0,
glyphHeightToWidth:1,
hasSun: true,
hasThunder: false,
isPolar: true,
rippleType: "circle",
rippleThickness: 0.2,
rippleScale: 30,
rippleSpeed: 0.2,
numColumns: 30,
palette: [
{r: 0.00, g: 0.00, b: 0.00, at: 0.0},
{r: 0.52, g: 0.17, b: 0.05, at: 0.4},
{r: 0.82, g: 0.37, b: 0.12, at: 0.7},
{r: 1.00, g: 0.74, b: 0.29, at: 0.9},
{r: 1.00, g: 1.00, b: 1.00, at: 1.0},
],
raindropLength: 0.5,
slant: 0,
},
nightmare: {
bloom: {
radius: 0.8,
strength: 2,
threshold: 0.5
},
cycleSpeed: 0.02,
cycleStyle: "cycleFasterWhenDimmed",
cursorEffectThreshold: 1,
brightnessOffset: 0.0,
brightnessMultiplier: 1.0,
fallSpeed: 2.0,
font: fonts.gothic,
glyphEdgeCrop: 0.0,
glyphHeightToWidth:1,
hasSun: false,
hasThunder: true,
isPolar: false,
rippleType: null,
rippleThickness: 0.2,
rippleScale: 30,
rippleSpeed: 0.2,
numColumns: 60,
palette: [
{r: 0.00, g: 0.00, b: 0.00, at: 0.0},
{r: 0.52, g: 0.00, b: 0.00, at: 0.2},
{r: 0.82, g: 0.05, b: 0.05, at: 0.4},
{r: 1.00, g: 0.60, b: 0.30, at: 0.8},
{r: 1.00, g: 1.00, b: 0.90, at: 1.0},
],
raindropLength: 0.6,
slant: 360 / 16,
},
classic: {
bloom: {
radius: 0.5,
strength: 2,
threshold: 0.3
},
cycleSpeed: 1,
cycleStyle: "cycleFasterWhenDimmed",
cursorEffectThreshold: 1,
brightnessOffset: 0.0,
brightnessMultiplier: 1.0,
fallSpeed: 1,
font: fonts.matrixcode,
glyphEdgeCrop: 0.0,
glyphHeightToWidth:1,
hasSun: false,
hasThunder: false,
isPolar: false,
rippleType: null,
rippleThickness: 0.2,
rippleScale: 30,
rippleSpeed: 0.2,
numColumns: 80,
palette: [
{r: 0/255, g: 0/255, b: 0/255, at: 0/16},
{r: 6/255, g: 16/255, b: 8/255, at: 1/16},
{r: 11/255, g: 28/255, b: 15/255, at: 2/16},
{r: 17/255, g: 41/255, b: 23/255, at: 3/16},
{r: 20/255, g: 58/255, b: 31/255, at: 4/16},
{r: 23/255, g: 84/255, b: 39/255, at: 5/16},
{r: 30/255, g: 113/255, b: 48/255, at: 6/16},
{r: 43/255, g: 142/255, b: 60/255, at: 7/16},
{r: 57/255, g: 160/255, b: 72/255, at: 8/16},
{r: 70/255, g: 175/255, b: 81/255, at: 9/16},
{r: 75/255, g: 187/255, b: 85/255, at: 10/16},
{r: 78/255, g: 196/255, b: 91/255, at: 11/16},
{r: 83/255, g: 203/255, b: 102/255, at: 12/16},
{r: 92/255, g: 212/255, b: 114/255, at: 13/16},
{r: 109/255, g: 223/255, b: 130/255, at: 14/16},
{r: 129/255, g: 232/255, b: 148/255, at: 15/16},
{r: 140/255, g: 235/255, b: 157/255, at: 16/16},
],
raindropLength: 1,
slant: 0,
},
operator: {
bloom: {
radius: 0.3,
strength: 1.45,
threshold: 0.0
},
cycleSpeed: 0.05,
cycleStyle: "cycleRandomly",
cursorEffectThreshold: 0.466,
brightnessOffset: 0.25,
brightnessMultiplier: 0.0,
fallSpeed: 0.6,
font: fonts.matrixcode,
glyphEdgeCrop: 0.15,
glyphHeightToWidth:1.35,
hasSun: false,
hasThunder: false,
isPolar: false,
rippleType: "box",
rippleThickness: 0.2,
rippleScale: 30,
rippleSpeed: 0.2,
numColumns: 108,
palette: [
{r: 0.00, g: 0.00, b: 0.00, at: 0.0},
{r: 0.18, g: 0.90, b: 0.35, at: 0.6},
{r: 0.90, g: 1.00, b: 0.90, at: 1.0},
],
raindropLength: 1.5,
slant: 0,
<head>
<title>Matrix digital rain</title>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"
/>
<style>
body {
background: black;
overflow: hidden;
margin: 0;
}
};
versions.throwback = versions.operator;
versions["1999"] = versions.classic;
const urlParams = new Map(window.location.href.replace(/^[^\?]+\?/, "").split("&").map(pair => pair.split("=")));
const getParam = (keyOrKeys, defaultValue) => {
if (Array.isArray(keyOrKeys)) {
const keys = keyOrKeys;
const key = keys.find(key => urlParams.has(key));
return key != null ? urlParams.get(key) : defaultValue;
} else {
const key = keyOrKeys;
return urlParams.has(key) ? urlParams.get(key) : defaultValue;
canvas {
width: 100vw;
height: 100vh;
}
};
</style>
</head>
<body>
<script src="lib/regl.min.js"></script>
<script type="module">
import { loadImages, makeFullScreenQuad } from "./js/utils.js";
import makeConfig from "./js/config.js";
import makeMatrixRenderer from "./js/renderer.js";
import makeBloomPass from "./js/bloomPass.js";
import makeColorPass from "./js/colorPass.js";
const version = versions[getParam("version", "classic")] || versions.classic;
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
document.addEventListener("touchmove", e => e.preventDefault(), {
passive: false
});
const animationSpeed = parseFloat(getParam("animationSpeed", 1));
const fallSpeed = parseFloat(getParam("fallSpeed", 1)) * version.fallSpeed;
const cycleSpeed = parseFloat(getParam("cycleSpeed", 1)) * version.cycleSpeed;
const numColumns = parseInt(getParam("width", version.numColumns));
const raindropLength = parseFloat(getParam(["raindropLength", "dropLength"], version.raindropLength));
const numFontColumns = 8;
const glyphSequenceLength = version.glyphSequenceLength;
const slant = parseFloat(getParam(["slant", "angle"], version.slant)) * Math.PI / 180;
const glyphEdgeCrop = parseFloat(getParam("encroach", version.glyphEdgeCrop));
const glyphHeightToWidth = parseFloat(getParam("stretch", version.glyphHeightToWidth));
const cursorEffectThreshold = getParam("cursorEffectThreshold", version.cursorEffectThreshold);
const bloomSize = Math.max(0.01, Math.min(1, parseFloat(getParam("bloomSize", 0.5))));
const regl = createREGL({
canvas,
extensions: ["OES_texture_half_float", "OES_texture_half_float_linear"],
optionalExtensions: [
"EXT_color_buffer_half_float",
"WEBGL_color_buffer_float",
"OES_standard_derivatives"
]
});
const effect = getParam("effect", "plain");
const [config, uniforms] = makeConfig(window.location.search, data =>
regl.texture({
data,
width: data.length / 3,
height: 1,
format: "rgb",
mag: "linear",
min: "linear"
})
);
document.ontouchmove = (e) => e.preventDefault();
const element = document.createElement("matrixcode");
document.body.appendChild(element);
const renderer = new THREE.WebGLRenderer({ stencil: false, depth: false, precision: "lowp" });
renderer.sortObjects = true;
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setPixelRatio(window.devicePixelRatio);
element.appendChild(renderer.domElement);
const composer = new THREE.EffectComposer( renderer );
const fontTexture = new THREE.TextureLoader().load( version.font.textureURL );
const matrixRenderer = makeMatrixRenderer(renderer, {
animationSpeed, fallSpeed, cycleSpeed,
cycleStyle: version.cycleStyle,
cursorEffectThreshold,
fontTexture,
glyphSequenceLength: version.font.sequenceLength,
glyphEdgeCrop,
glyphHeightToWidth,
hasSun: version.hasSun,
hasThunder: version.hasThunder,
isPolar: version.isPolar,
rippleType: version.rippleType,
rippleThickness: version.rippleThickness,
rippleScale: version.rippleScale,
rippleSpeed: version.rippleSpeed,
brightnessMultiplier: version.brightnessMultiplier,
brightnessOffset: version.brightnessOffset,
numColumns,
numFontColumns,
raindropLength,
showComputationTexture: effect === "none",
slant,
});
matrixRenderer.pass.renderToScreen = false;
composer.addPass( matrixRenderer.pass );
const bloomPass = new THREE.UnrealBloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight ), version.bloom.strength, version.bloom.radius, version.bloom.threshold );
if (effect !== "none") {
composer.addPass( bloomPass );
}
switch (effect) {
case "plain":
composer.addPass(new THREE.ColorMapPass(version.palette, 0.05, 100));
break;
case "pride":
composer.addPass(new THREE.HorizontalColorationPass([
new THREE.Vector3(1, 0, 0),
new THREE.Vector3(1, 0.5, 0),
new THREE.Vector3(1, 1, 0),
new THREE.Vector3(0, 1, 0),
new THREE.Vector3(0, 0, 1),
new THREE.Vector3(0.8, 0, 1),
], 0.1));
break;
case "customStripes":
const flagColorData = getParam("colors", "0.4,0.15,0.1,0.4,0.15,0.1,0.8,0.8,0.6,0.8,0.8,0.6,1.0,0.7,0.8,1.0,0.7,0.8,").split(",").map(parseFloat);
const numFlagColors = Math.floor(flagColorData.length / 3);
const colors = [];
for (let i = 0; i < numFlagColors; i++) {
colors.push(new THREE.Vector3(flagColorData[i * 3 + 0], flagColorData[i * 3 + 1], flagColorData[i * 3 + 2]));
const fullScreenQuad = makeFullScreenQuad(regl, uniforms);
const renderer = makeMatrixRenderer(regl, config);
const bloomPass = makeBloomPass(regl, config, renderer.fbo);
const colorPass = makeColorPass(regl, config, bloomPass.fbo);
const drawToScreen = regl({
uniforms: {
tex: colorPass.fbo
}
composer.addPass(new THREE.HorizontalColorationPass(colors, 0.1));
break;
case "none":
break;
case "image":
const imageURL = getParam("url", "https://upload.wikimedia.org/wikipedia/commons/0/0a/Flammarion_Colored.jpg");
window.texture2 = new THREE.TextureLoader().load( imageURL );
composer.addPass(new THREE.ImageOverlayPass(texture2));
break;
}
});
composer.passes[composer.passes.length - 1].renderToScreen = true;
const resize = () => {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
};
window.onresize = resize;
resize();
const windowResize = () => {
const [width, height, pixelRatio] = [window.innerWidth, window.innerHeight, window.devicePixelRatio];
matrixRenderer.resize(width, height);
renderer.setSize(width, height);
composer.setSize(width * pixelRatio, height * pixelRatio);
bloomPass.setSize( window.innerWidth * pixelRatio * bloomSize, window.innerHeight * pixelRatio * bloomSize );
}
window.addEventListener("resize", windowResize, false);
window.addEventListener("orientationchange", windowResize, false);
windowResize();
fullScreenQuad(renderer.update);
const render = () => {
requestAnimationFrame(render);
matrixRenderer.render();
composer.render();
}
render();
document.body.onload = async () => {
const resources = await loadImages(regl, {
msdfTex: config.glyphTexURL,
backgroundTex:
config.effect === "image" ? config.backgroundImage : null
});
</script>
</body></html>
const loop = regl.frame(({ viewportWidth, viewportHeight }) => {
renderer.resize(viewportWidth, viewportHeight);
bloomPass.resize(viewportWidth, viewportHeight);
colorPass.resize(viewportWidth, viewportHeight);
fullScreenQuad(() => {
renderer.update();
renderer.render(resources);
bloomPass.render();
colorPass.render(resources);
drawToScreen();
});
});
};
</script>
</body>
</html>

View File

@@ -1,94 +0,0 @@
/**
* @author rezmason
*/
const easeInOutQuad = input => {
input = Math.max(0, Math.min(1, input));
if (input < 0.5) {
return 2 * input * input;
}
input -= 1;
return 1 - 2 * input * input;
}
const ARRAY_SIZE = 2048;
THREE.ColorMapPass = function (entries, ditherMagnitude = 1, graininess = 100) {
const colors = Array(ARRAY_SIZE).fill().map(_ => new THREE.Vector3(0, 0, 0));
const sortedEntries = entries.slice().sort((e1, e2) => e1.at - e2.at).map(entry => ({
color: new THREE.Vector3(entry.r, entry.g, entry.b),
arrayIndex: Math.floor(Math.max(Math.min(1, entry.at), 0) * (ARRAY_SIZE - 1))
}));
sortedEntries.unshift({color:sortedEntries[0].color, arrayIndex:0});
sortedEntries.push({color:sortedEntries[sortedEntries.length - 1].color, arrayIndex:ARRAY_SIZE - 1});
sortedEntries.forEach((entry, index) => {
colors[entry.arrayIndex].copy(entry.color);
if (index + 1 < sortedEntries.length) {
const nextEntry = sortedEntries[index + 1];
const diff = nextEntry.arrayIndex - entry.arrayIndex;
for (let i = 0; i < diff; i++) {
colors[entry.arrayIndex + i].lerpVectors(entry.color, nextEntry.color, i / diff);
}
}
});
const values = new Uint8Array([].concat(...colors.map(color => color.toArray().map(component => Math.floor(component * 255)))));
this.dataTexture = new THREE.DataTexture(
values,
values.length / 3,
1,
THREE.RGBFormat,
THREE.UnsignedByteType,
THREE.UVMapping);
this.dataTexture.magFilter = THREE.LinearFilter;
this.dataTexture.needsUpdate = true;
this.graininess = graininess;
this.shader = {
uniforms: {
tDiffuse: { value: null },
tColorData: { value: this.dataTexture },
ditherMagnitude: { value: ditherMagnitude },
tTime: { value: 0 }
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4( position, 1.0 );
}
`,
fragmentShader: `
#define PI 3.14159265359
uniform sampler2D tDiffuse;
uniform sampler2D tColorData;
uniform float ditherMagnitude;
uniform float tTime;
varying vec2 vUv;
highp float rand( const in vec2 uv, const in float t ) {
const highp float a = 12.9898, b = 78.233, c = 43758.5453;
highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );
return fract(sin(sn) * c + t);
}
void main() {
gl_FragColor = texture2D( tColorData, vec2( texture2D( tDiffuse, vUv ).r - rand( gl_FragCoord.xy, tTime ) * ditherMagnitude, 0.0 ) );
}
`
};
THREE.ShaderPass.call(this, this.shader);
};
THREE.ColorMapPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.ColorMapPass,
render: function() {
this.uniforms[ "tColorData" ].value = this.dataTexture;
this.uniforms[ "tTime" ].value = (Date.now() % this.graininess) / this.graininess;
THREE.ShaderPass.prototype.render.call(this, ...arguments);
}
});

View File

@@ -1,46 +0,0 @@
/**
* @author alteredq / http://alteredqualia.com/
*
* Full-screen textured quad shader
*/
THREE.CopyShader = {
uniforms: {
"tDiffuse": { value: null },
"opacity": { value: 1.0 }
},
vertexShader: [
"varying vec2 vUv;",
"void main() {",
"vUv = uv;",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}"
].join( "\n" ),
fragmentShader: [
"uniform float opacity;",
"uniform sampler2D tDiffuse;",
"varying vec2 vUv;",
"void main() {",
"vec4 texel = texture2D( tDiffuse, vUv );",
"gl_FragColor = opacity * texel;",
"}"
].join( "\n" )
};

View File

@@ -1,189 +0,0 @@
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.EffectComposer = function ( renderer, renderTarget ) {
this.renderer = renderer;
if ( renderTarget === undefined ) {
var parameters = {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat,
stencilBuffer: false
};
var size = renderer.getDrawingBufferSize();
renderTarget = new THREE.WebGLRenderTarget( size.width, size.height, parameters );
renderTarget.texture.name = 'EffectComposer.rt1';
}
this.renderTarget1 = renderTarget;
this.renderTarget2 = renderTarget.clone();
this.renderTarget2.texture.name = 'EffectComposer.rt2';
this.writeBuffer = this.renderTarget1;
this.readBuffer = this.renderTarget2;
this.passes = [];
// dependencies
if ( THREE.CopyShader === undefined ) {
console.error( 'THREE.EffectComposer relies on THREE.CopyShader' );
}
if ( THREE.ShaderPass === undefined ) {
console.error( 'THREE.EffectComposer relies on THREE.ShaderPass' );
}
this.copyPass = new THREE.ShaderPass( THREE.CopyShader );
};
Object.assign( THREE.EffectComposer.prototype, {
swapBuffers: function () {
var tmp = this.readBuffer;
this.readBuffer = this.writeBuffer;
this.writeBuffer = tmp;
},
addPass: function ( pass ) {
this.passes.push( pass );
var size = this.renderer.getDrawingBufferSize();
pass.setSize( size.width, size.height );
},
insertPass: function ( pass, index ) {
this.passes.splice( index, 0, pass );
},
render: function ( delta ) {
var maskActive = false;
var pass, i, il = this.passes.length;
for ( i = 0; i < il; i ++ ) {
pass = this.passes[ i ];
if ( pass.enabled === false ) continue;
pass.render( this.renderer, this.writeBuffer, this.readBuffer, delta, maskActive );
if ( pass.needsSwap ) {
if ( maskActive ) {
var context = this.renderer.context;
context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );
this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, delta );
context.stencilFunc( context.EQUAL, 1, 0xffffffff );
}
this.swapBuffers();
}
if ( THREE.MaskPass !== undefined ) {
if ( pass instanceof THREE.MaskPass ) {
maskActive = true;
} else if ( pass instanceof THREE.ClearMaskPass ) {
maskActive = false;
}
}
}
},
reset: function ( renderTarget ) {
if ( renderTarget === undefined ) {
var size = this.renderer.getDrawingBufferSize();
renderTarget = this.renderTarget1.clone();
renderTarget.setSize( size.width, size.height );
}
this.renderTarget1.dispose();
this.renderTarget2.dispose();
this.renderTarget1 = renderTarget;
this.renderTarget2 = renderTarget.clone();
this.writeBuffer = this.renderTarget1;
this.readBuffer = this.renderTarget2;
},
setSize: function ( width, height ) {
this.renderTarget1.setSize( width, height );
this.renderTarget2.setSize( width, height );
for ( var i = 0; i < this.passes.length; i ++ ) {
this.passes[ i ].setSize( width, height );
}
}
} );
THREE.Pass = function () {
// if set to true, the pass is processed by the composer
this.enabled = true;
// if set to true, the pass indicates to swap read and write buffer after rendering
this.needsSwap = true;
// if set to true, the pass clears its buffer before rendering
this.clear = false;
// if set to true, the result of the pass is rendered to screen
this.renderToScreen = false;
};
Object.assign( THREE.Pass.prototype, {
setSize: function ( width, height ) {},
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
console.error( 'THREE.Pass: .render() must be implemented in derived pass.' );
}
} );

View File

@@ -1,368 +0,0 @@
/**
* @author yomboprime https://github.com/yomboprime
*
* GPUComputationRenderer, based on SimulationRenderer by zz85
*
* The GPUComputationRenderer uses the concept of variables. These variables are RGBA float textures that hold 4 floats
* for each compute element (texel)
*
* Each variable has a fragment shader that defines the computation made to obtain the variable in question.
* You can use as many variables you need, and make dependencies so you can use textures of other variables in the shader
* (the sampler uniforms are added automatically) Most of the variables will need themselves as dependency.
*
* The renderer has actually two render targets per variable, to make ping-pong. Textures from the current frame are used
* as inputs to render the textures of the next frame.
*
* The render targets of the variables can be used as input textures for your visualization shaders.
*
* Variable names should be valid identifiers and should not collide with THREE GLSL used identifiers.
* a common approach could be to use 'texture' prefixing the variable name; i.e texturePosition, textureVelocity...
*
* The size of the computation (sizeX * sizeY) is defined as 'resolution' automatically in the shader. For example:
* #DEFINE resolution vec2( 1024.0, 1024.0 )
*
* -------------
*
* Basic use:
*
* // Initialization...
*
* // Create computation renderer
* var gpuCompute = new GPUComputationRenderer( 1024, 1024, renderer );
*
* // Create initial state float textures
* var pos0 = gpuCompute.createTexture();
* var vel0 = gpuCompute.createTexture();
* // and fill in here the texture data...
*
* // Add texture variables
* var velVar = gpuCompute.addVariable( "textureVelocity", fragmentShaderVel, pos0 );
* var posVar = gpuCompute.addVariable( "texturePosition", fragmentShaderPos, vel0 );
*
* // Add variable dependencies
* gpuCompute.setVariableDependencies( velVar, [ velVar, posVar ] );
* gpuCompute.setVariableDependencies( posVar, [ velVar, posVar ] );
*
* // Add custom uniforms
* velVar.material.uniforms.time = { value: 0.0 };
*
* // Check for completeness
* var error = gpuCompute.init();
* if ( error !== null ) {
* console.error( error );
* }
*
*
* // In each frame...
*
* // Compute!
* gpuCompute.compute();
*
* // Update texture uniforms in your visualization materials with the gpu renderer output
* myMaterial.uniforms.myTexture.value = gpuCompute.getCurrentRenderTarget( posVar ).texture;
*
* // Do your rendering
* renderer.render( myScene, myCamera );
*
* -------------
*
* Also, you can use utility functions to create ShaderMaterial and perform computations (rendering between textures)
* Note that the shaders can have multiple input textures.
*
* var myFilter1 = gpuCompute.createShaderMaterial( myFilterFragmentShader1, { theTexture: { value: null } } );
* var myFilter2 = gpuCompute.createShaderMaterial( myFilterFragmentShader2, { theTexture: { value: null } } );
*
* var inputTexture = gpuCompute.createTexture();
*
* // Fill in here inputTexture...
*
* myFilter1.uniforms.theTexture.value = inputTexture;
*
* var myRenderTarget = gpuCompute.createRenderTarget();
* myFilter2.uniforms.theTexture.value = myRenderTarget.texture;
*
* var outputRenderTarget = gpuCompute.createRenderTarget();
*
* // Now use the output texture where you want:
* myMaterial.uniforms.map.value = outputRenderTarget.texture;
*
* // And compute each frame, before rendering to screen:
* gpuCompute.doRenderTarget( myFilter1, myRenderTarget );
* gpuCompute.doRenderTarget( myFilter2, outputRenderTarget );
*
*
*
* @param {int} sizeX Computation problem size is always 2d: sizeX * sizeY elements.
* @param {int} sizeY Computation problem size is always 2d: sizeX * sizeY elements.
* @param {WebGLRenderer} renderer The renderer
*/
function GPUComputationRenderer( sizeX, sizeY, renderer ) {
this.variables = [];
this.currentTextureIndex = 0;
var scene = new THREE.Scene();
var camera = new THREE.Camera();
camera.position.z = 1;
var passThruUniforms = {
texture: { value: null }
};
var passThruShader = createShaderMaterial( getPassThroughFragmentShader(), passThruUniforms );
var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), passThruShader );
scene.add( mesh );
this.addVariable = function( variableName, computeFragmentShader, initialValueTexture ) {
var material = this.createShaderMaterial( computeFragmentShader );
var variable = {
name: variableName,
initialValueTexture: initialValueTexture,
material: material,
dependencies: null,
renderTargets: [],
wrapS: null,
wrapT: null,
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter
};
this.variables.push( variable );
return variable;
};
this.setVariableDependencies = function( variable, dependencies ) {
variable.dependencies = dependencies;
};
this.init = function() {
if ( ! renderer.extensions.get( "OES_texture_float" ) ) {
return "No OES_texture_float support for float textures.";
}
if ( renderer.capabilities.maxVertexTextures === 0 ) {
return "No support for vertex shader textures.";
}
for ( var i = 0; i < this.variables.length; i++ ) {
var variable = this.variables[ i ];
// Creates rendertargets and initialize them with input texture
variable.renderTargets[ 0 ] = this.createRenderTarget( sizeX, sizeY, variable.wrapS, variable.wrapT, variable.minFilter, variable.magFilter );
variable.renderTargets[ 1 ] = this.createRenderTarget( sizeX, sizeY, variable.wrapS, variable.wrapT, variable.minFilter, variable.magFilter );
this.renderTexture( variable.initialValueTexture, variable.renderTargets[ 0 ] );
this.renderTexture( variable.initialValueTexture, variable.renderTargets[ 1 ] );
// Adds dependencies uniforms to the ShaderMaterial
var material = variable.material;
var uniforms = material.uniforms;
if ( variable.dependencies !== null ) {
for ( var d = 0; d < variable.dependencies.length; d++ ) {
var depVar = variable.dependencies[ d ];
if ( depVar.name !== variable.name ) {
// Checks if variable exists
var found = false;
for ( var j = 0; j < this.variables.length; j++ ) {
if ( depVar.name === this.variables[ j ].name ) {
found = true;
break;
}
}
if ( ! found ) {
return "Variable dependency not found. Variable=" + variable.name + ", dependency=" + depVar.name;
}
}
uniforms[ depVar.name ] = { value: null };
material.fragmentShader = "\nuniform sampler2D " + depVar.name + ";\n" + material.fragmentShader;
}
}
}
this.currentTextureIndex = 0;
return null;
};
this.compute = function() {
var currentTextureIndex = this.currentTextureIndex;
var nextTextureIndex = this.currentTextureIndex === 0 ? 1 : 0;
for ( var i = 0, il = this.variables.length; i < il; i++ ) {
var variable = this.variables[ i ];
// Sets texture dependencies uniforms
if ( variable.dependencies !== null ) {
var uniforms = variable.material.uniforms;
for ( var d = 0, dl = variable.dependencies.length; d < dl; d++ ) {
var depVar = variable.dependencies[ d ];
uniforms[ depVar.name ].value = depVar.renderTargets[ currentTextureIndex ].texture;
}
}
// Performs the computation for this variable
this.doRenderTarget( variable.material, variable.renderTargets[ nextTextureIndex ] );
}
this.currentTextureIndex = nextTextureIndex;
};
this.getCurrentRenderTarget = function( variable ) {
return variable.renderTargets[ this.currentTextureIndex ];
};
this.getAlternateRenderTarget = function( variable ) {
return variable.renderTargets[ this.currentTextureIndex === 0 ? 1 : 0 ];
};
function addResolutionDefine( materialShader ) {
materialShader.defines.resolution = 'vec2( ' + sizeX.toFixed( 1 ) + ', ' + sizeY.toFixed( 1 ) + " )";
}
this.addResolutionDefine = addResolutionDefine;
// The following functions can be used to compute things manually
function createShaderMaterial( computeFragmentShader, uniforms ) {
uniforms = uniforms || {};
var material = new THREE.ShaderMaterial( {
uniforms: uniforms,
vertexShader: getPassThroughVertexShader(),
fragmentShader: computeFragmentShader
} );
addResolutionDefine( material );
return material;
}
this.createShaderMaterial = createShaderMaterial;
this.createRenderTarget = function( sizeXTexture, sizeYTexture, wrapS, wrapT, minFilter, magFilter ) {
sizeXTexture = sizeXTexture || sizeX;
sizeYTexture = sizeYTexture || sizeY;
wrapS = wrapS || THREE.ClampToEdgeWrapping;
wrapT = wrapT || THREE.ClampToEdgeWrapping;
minFilter = minFilter || THREE.NearestFilter;
magFilter = magFilter || THREE.NearestFilter;
var renderTarget = new THREE.WebGLRenderTarget( sizeXTexture, sizeYTexture, {
wrapS: wrapS,
wrapT: wrapT,
minFilter: minFilter,
magFilter: magFilter,
format: THREE.RGBAFormat,
type: ( /(iPad|iPhone|iPod)/g.test( navigator.userAgent ) ) ? THREE.HalfFloatType : THREE.FloatType,
stencilBuffer: false,
depthBuffer: false
} );
return renderTarget;
};
this.createTexture = function() {
var a = new Float32Array( sizeX * sizeY * 4 );
var texture = new THREE.DataTexture( a, sizeX, sizeY, THREE.RGBAFormat, THREE.FloatType );
texture.needsUpdate = true;
return texture;
};
this.renderTexture = function( input, output ) {
// Takes a texture, and render out in rendertarget
// input = Texture
// output = RenderTarget
passThruUniforms.texture.value = input;
this.doRenderTarget( passThruShader, output);
passThruUniforms.texture.value = null;
};
this.doRenderTarget = function( material, output ) {
mesh.material = material;
renderer.render( scene, camera, output );
mesh.material = passThruShader;
};
// Shaders
function getPassThroughVertexShader() {
return "void main() {\n" +
"\n" +
" gl_Position = vec4( position, 1.0 );\n" +
"\n" +
"}\n";
}
function getPassThroughFragmentShader() {
return "uniform sampler2D texture;\n" +
"\n" +
"void main() {\n" +
"\n" +
" vec2 uv = gl_FragCoord.xy / resolution.xy;\n" +
"\n" +
" gl_FragColor = texture2D( texture, uv );\n" +
"\n" +
"}\n";
}
}

View File

@@ -1,64 +0,0 @@
/**
* @author rezmason
*/
THREE.HorizontalColorationPass = function (colors, ditherMagnitude = 1) {
const values = new Uint8Array([].concat(...colors.map(color => color.toArray().map(component => Math.floor(component * 255)))));
this.dataTexture = new THREE.DataTexture(
values,
values.length / 3,
1,
THREE.RGBFormat,
THREE.UnsignedByteType,
THREE.UVMapping);
this.dataTexture.magFilter = THREE.LinearFilter;
this.dataTexture.needsUpdate = true;
this.shader = {
uniforms: {
tDiffuse: { value: null },
tColorData: { value: this.dataTexture },
ditherMagnitude: { value: ditherMagnitude },
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4( position, 1.0 );
}
`,
fragmentShader: `
#define PI 3.14159265359
uniform sampler2D tDiffuse;
uniform sampler2D tColorData;
uniform float ditherMagnitude;
varying vec2 vUv;
highp float rand( const in vec2 uv ) {
const highp float a = 12.9898, b = 78.233, c = 43758.5453;
highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );
return fract(sin(sn) * c);
}
void main() {
float value = texture2D(tDiffuse, vUv).r;
vec3 value2 = texture2D(tColorData, vUv).rgb - rand( gl_FragCoord.xy ) * ditherMagnitude;
gl_FragColor = vec4(value2 * value, 1.0);
}
`
};
THREE.ShaderPass.call(this, this.shader);
};
THREE.HorizontalColorationPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.HorizontalColorationPass,
render: function() {
this.uniforms[ "tColorData" ].value = this.dataTexture;
THREE.ShaderPass.prototype.render.call(this, ...arguments);
}
});

View File

@@ -1,41 +0,0 @@
/**
* @author rezmason
*/
THREE.ImageOverlayPass = function (texture) {
this.texture = texture;
this.shader = {
uniforms: {
tDiffuse: { value: null },
map: { value: this.texture },
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4( position, 1.0 );
}
`,
fragmentShader: `
uniform sampler2D tDiffuse;
uniform sampler2D map;
varying vec2 vUv;
void main() {
gl_FragColor = vec4(texture2D(map, vUv).rgb * (pow(texture2D(tDiffuse, vUv).r, 1.5) * 0.995 + 0.005), 1.0);
}
`
};
THREE.ShaderPass.call(this, this.shader);
};
THREE.ImageOverlayPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.ImageOverlayPass,
render: function() {
this.uniforms[ "map" ].value = this.texture;
THREE.ShaderPass.prototype.render.call(this, ...arguments);
}
});

View File

@@ -1,64 +0,0 @@
/**
* @author bhouston / http://clara.io/
*
* Luminosity
* http://en.wikipedia.org/wiki/Luminosity
*/
THREE.LuminosityHighPassShader = {
shaderID: "luminosityHighPass",
uniforms: {
"tDiffuse": { type: "t", value: null },
"luminosityThreshold": { type: "f", value: 1.0 },
"smoothWidth": { type: "f", value: 1.0 },
"defaultColor": { type: "c", value: new THREE.Color( 0x000000 ) },
"defaultOpacity": { type: "f", value: 0.0 }
},
vertexShader: [
"varying vec2 vUv;",
"void main() {",
"vUv = uv;",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}"
].join("\n"),
fragmentShader: [
"uniform sampler2D tDiffuse;",
"uniform vec3 defaultColor;",
"uniform float defaultOpacity;",
"uniform float luminosityThreshold;",
"uniform float smoothWidth;",
"varying vec2 vUv;",
"void main() {",
"vec4 texel = texture2D( tDiffuse, vUv );",
"vec3 luma = vec3( 0.299, 0.587, 0.114 );",
"float v = dot( texel.xyz, luma );",
"vec4 outputColor = vec4( defaultColor.rgb, defaultOpacity );",
"float alpha = smoothstep( luminosityThreshold, luminosityThreshold + smoothWidth, v );",
"gl_FragColor = mix( outputColor, texel, alpha );",
"}"
].join("\n")
};

View File

@@ -1,397 +0,0 @@
const makeMatrixRenderer = (renderer, {
fontTexture,
numColumns,
animationSpeed, fallSpeed, cycleSpeed,
glyphSequenceLength,
numFontColumns,
hasThunder,
hasSun,
isPolar,
slant,
glyphHeightToWidth,
glyphEdgeCrop,
cursorEffectThreshold,
showComputationTexture,
raindropLength,
cycleStyle,
rippleType,
rippleScale,
rippleSpeed,
rippleThickness,
brightnessMultiplier,
brightnessOffset,
}) => {
const matrixRenderer = {};
const camera = new THREE.OrthographicCamera( -0.5, 0.5, 0.5, -0.5, 0.0001, 10000 );
const scene = new THREE.Scene();
const gpuCompute = new GPUComputationRenderer( numColumns, numColumns, renderer );
const glyphValue = gpuCompute.createTexture();
const pixels = glyphValue.image.data;
const scramble = i => Math.sin(i) * 0.5 + 0.5;
for (let i = 0; i < numColumns * numColumns; i++) {
pixels[i * 4 + 0] = 0;
pixels[i * 4 + 1] = showComputationTexture ? 0.5 : scramble(i);
pixels[i * 4 + 2] = 0;
pixels[i * 4 + 3] = 0;
}
const glyphVariable = gpuCompute.addVariable(
"glyph",
`
precision highp float;
#define PI 3.14159265359
#define SQRT_2 1.4142135623730951
#define SQRT_5 2.23606797749979
uniform bool hasSun;
uniform bool hasThunder;
uniform bool showComputationTexture;
uniform float brightnessChangeBias;
uniform float brightnessMultiplier;
uniform float brightnessOffset;
uniform float cursorEffectThreshold;
uniform float time;
uniform float animationSpeed;
uniform float cycleSpeed;
uniform float deltaTime;
uniform float fallSpeed;
uniform float raindropLength;
uniform float glyphHeightToWidth;
uniform float glyphSequenceLength;
uniform float numFontColumns;
uniform int cycleStyle;
uniform float rippleScale;
uniform float rippleSpeed;
uniform float rippleThickness;
uniform int rippleType;
highp float rand( const in vec2 uv ) {
const highp float a = 12.9898, b = 78.233, c = 43758.5453;
highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );
return fract(sin(sn) * c);
}
float max2(vec2 v) {
return max(v.x, v.y);
}
vec2 rand2(vec2 p) {
return fract(vec2(sin(p.x * 591.32 + p.y * 154.077), cos(p.x * 391.32 + p.y * 49.077)));
}
highp float blast( const in float x, const in float power ) {
return pow(pow(pow(x, power), power), power);
}
float ripple(vec2 uv, float simTime) {
if (rippleType == -1) {
return 0.;
}
float rippleTime = (simTime + 0.2 * sin(simTime * 2.0)) * rippleSpeed + 1.;
vec2 offset = rand2(vec2(floor(rippleTime), 0.)) - 0.5;
vec2 ripplePos = uv + offset;
float rippleDistance;
if (rippleType == 0) {
rippleDistance = max2(abs(ripplePos) * vec2(1.0, glyphHeightToWidth));
} else if (rippleType == 1) {
rippleDistance = length(ripplePos);
}
float rippleValue = fract(rippleTime) * rippleScale - rippleDistance;
if (rippleValue > 0. && rippleValue < rippleThickness) {
return 0.75;
} else {
return 0.;
}
}
void main() {
vec2 cellSize = 1.0 / resolution.xy;
vec2 uv = (gl_FragCoord.xy) * cellSize;
float columnTimeOffset = rand(vec2(gl_FragCoord.x, 0.0));
float columnSpeedOffset = rand(vec2(gl_FragCoord.x + 0.1, 0.0));
vec4 data = texture2D( glyph, uv );
float brightness = data.r;
float glyphCycle = data.g;
float simTime = time * 0.0005 * animationSpeed;
float columnTime = (columnTimeOffset * 1000.0 + simTime * fallSpeed) * (0.5 + columnSpeedOffset * 0.5) + (sin(simTime * fallSpeed * 2.0 * columnSpeedOffset) * 0.2);
float glyphTime = (gl_FragCoord.y * 0.01 + columnTime) / raindropLength;
float value = 1.0 - fract((glyphTime + 0.3 * sin(SQRT_2 * glyphTime) + 0.2 * sin(SQRT_5 * glyphTime)));
float newBrightness = 3.0 * log(value * 1.25);
if (hasSun) {
newBrightness = pow(fract(newBrightness * 0.5), 3.0) * uv.y * 2.0;
}
if (hasThunder) {
vec2 distVec = (gl_FragCoord.xy / resolution.xy - vec2(0.5, 1.0)) * vec2(1.0, 2.0);
float thunder = (blast(sin(SQRT_5 * simTime * 2.0), 10.0) + blast(sin(SQRT_2 * simTime * 2.0), 10.0));
thunder *= 30.0 * (1.0 - 1.0 * length(distVec));
newBrightness *= max(0.0, thunder) * 1.0 + 0.7;
if (newBrightness > brightness) {
brightness = newBrightness;
} else {
brightness = mix(brightness, newBrightness, brightnessChangeBias * 0.1);
}
} else {
brightness = mix(brightness, newBrightness, brightnessChangeBias);
}
float glyphCycleSpeed = 0.0;
if (cycleStyle == 1) {
glyphCycleSpeed = fract((glyphTime + 0.7 * sin(SQRT_2 * glyphTime) + 1.1 * sin(SQRT_5 * glyphTime))) * 0.75;
} else if (cycleStyle == 0) {
if (brightness > 0.0) glyphCycleSpeed = pow(1.0 - brightness, 4.0);
}
glyphCycle = fract(glyphCycle + deltaTime * cycleSpeed * 0.2 * glyphCycleSpeed);
float symbol = floor(glyphSequenceLength * glyphCycle);
float symbolX = mod(symbol, numFontColumns);
float symbolY = ((numFontColumns - 1.0) - (symbol - symbolX) / numFontColumns);
float effect = 0.;
effect += ripple(gl_FragCoord.xy / resolution.xy * 2.0 - 1.0, simTime);
if (brightness >= cursorEffectThreshold) {
effect = 1.0;
}
if (brightness > -1.) {
brightness = brightness * brightnessMultiplier + brightnessOffset;
}
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
gl_FragColor.r = brightness;
gl_FragColor.g = glyphCycle;
if (showComputationTexture) {
// Better use of the blue channel, for show and tell
gl_FragColor.b = min(1.0, glyphCycleSpeed);
gl_FragColor.a = 1.0;
} else {
gl_FragColor.b = symbolY * numFontColumns + symbolX;
gl_FragColor.a = effect;
}
}
`
,
glyphValue
);
gpuCompute.setVariableDependencies( glyphVariable, [ glyphVariable ] );
const brightnessChangeBias = (animationSpeed * fallSpeed) == 0 ? 1 : Math.min(1, Math.abs(animationSpeed * fallSpeed));
let cycleStyleInt;
switch (cycleStyle) {
case "cycleFasterWhenDimmed":
cycleStyleInt = 0;
break;
case "cycleRandomly":
default:
cycleStyleInt = 1;
break;
}
let rippleTypeInt;
switch (rippleType) {
case "box":
rippleTypeInt = 0;
break;
case "circle":
rippleTypeInt = 1;
break;
default:
rippleTypeInt = -1;
}
Object.assign(glyphVariable.material.uniforms, {
time: { type: "f", value: 0 },
deltaTime: { type: "f", value: 0.01 },
animationSpeed: { type: "f", value: animationSpeed },
fallSpeed: { type: "f", value: fallSpeed },
cycleSpeed: {type: "f", value: cycleSpeed },
glyphSequenceLength: { type: "f", value: glyphSequenceLength },
numFontColumns: {type: "f", value: numFontColumns },
raindropLength: {type: "f", value: raindropLength },
brightnessChangeBias: { type: "f", value: brightnessChangeBias },
rippleThickness: { type: "f", value: rippleThickness},
rippleScale: { type: "f", value: rippleScale},
rippleSpeed: { type: "f", value: rippleSpeed},
cursorEffectThreshold: { type: "f", value: cursorEffectThreshold},
brightnessMultiplier: { type: "f", value: brightnessMultiplier},
brightnessOffset: { type: "f", value: brightnessOffset},
glyphHeightToWidth: {type: "f", value: glyphHeightToWidth},
hasSun: { type: "b", value: hasSun },
hasThunder: { type: "b", value: hasThunder },
rippleType: { type: "i", value: rippleTypeInt },
showComputationTexture: { type: "b", value: showComputationTexture },
cycleStyle: { type: "i", value: cycleStyleInt },
});
const error = gpuCompute.init();
if ( error !== null ) {
console.error( error );
}
const glyphRTT = gpuCompute.getCurrentRenderTarget( glyphVariable ).texture;
const mesh = new THREE.Mesh(
new THREE.PlaneBufferGeometry(),
new THREE.RawShaderMaterial({
uniforms: {
glyphs: { type: "t", value: glyphRTT },
msdf: { type: "t", value: fontTexture },
numColumns: {type: "f", value: numColumns},
numFontColumns: {type: "f", value: numFontColumns},
resolution: {type: "v2", value: new THREE.Vector2() },
slant: {type: "v2", value: new THREE.Vector2(Math.cos(slant), Math.sin(slant)) },
glyphHeightToWidth: {type: "f", value: glyphHeightToWidth},
glyphEdgeCrop: {type: "f", value: glyphEdgeCrop},
isPolar: { type: "b", value: isPolar },
showComputationTexture: { type: "b", value: showComputationTexture },
},
vertexShader: `
attribute vec2 uv;
attribute vec3 position;
uniform vec2 resolution;
varying vec2 vUV;
void main() {
vUV = uv;
gl_Position = vec4( resolution * position.xy, 0.0, 1.0 );
}
`,
fragmentShader: `
#define PI 3.14159265359
#ifdef GL_OES_standard_derivatives
#extension GL_OES_standard_derivatives: enable
#endif
precision lowp float;
uniform sampler2D msdf;
uniform sampler2D glyphs;
uniform float numColumns;
uniform float numFontColumns;
uniform vec2 slant;
uniform float glyphHeightToWidth;
uniform float glyphEdgeCrop;
uniform bool isPolar;
uniform bool showComputationTexture;
varying vec2 vUV;
float median(float r, float g, float b) {
return max(min(r, g), min(max(r, g), b));
}
void main() {
vec2 uv = vUV;
if (isPolar) {
uv -= 0.5;
uv *= 0.5;
uv.y -= 0.5;
float radius = length(uv);
float angle = atan(uv.y, uv.x) / (2. * PI) + 0.5;
uv = vec2(angle * 4. - 0.5, 1.25 - radius * 1.5);
} else {
uv = vec2(
(uv.x - 0.5) * slant.x + (uv.y - 0.5) * slant.y,
(uv.y - 0.5) * slant.x - (uv.x - 0.5) * slant.y
) * 0.75 + 0.5;
}
uv.y /= glyphHeightToWidth;
vec4 glyph = texture2D(glyphs, uv);
if (showComputationTexture) {
gl_FragColor = glyph;
return;
}
// Unpack the values from the font texture
float brightness = glyph.r;
float effect = glyph.a;
brightness = max(effect, brightness);
float symbolIndex = glyph.b;
vec2 symbolUV = vec2(mod(symbolIndex, numFontColumns), floor(symbolIndex / numFontColumns));
vec2 glyphUV = fract(uv * numColumns);
glyphUV -= 0.5;
glyphUV *= clamp(1.0 - glyphEdgeCrop, 0.0, 1.0);
glyphUV += 0.5;
vec4 sample = texture2D(msdf, (glyphUV + symbolUV) / numFontColumns);
// The rest is straight up MSDF
float sigDist = median(sample.r, sample.g, sample.b) - 0.5;
float alpha = clamp(sigDist/fwidth(sigDist) + 0.5, 0.0, 1.0);
gl_FragColor = vec4(vec3(brightness * alpha), 1.0);
}
`
})
);
mesh.frustumCulled = false;
scene.add( mesh );
let start = NaN;
let last = NaN;
matrixRenderer.pass = new THREE.RenderPass( scene, camera );
matrixRenderer.render = () => {
if (isNaN(start)) {
start = Date.now();
last = 0;
}
const now = Date.now() - start;
if (now - last > 50) {
last = now;
return;
}
const deltaTime = ((now - last > 1000) ? 0 : now - last) / 1000 * animationSpeed;
last = now;
glyphVariable.material.uniforms.time.value = now;
glyphVariable.material.uniforms.deltaTime.value = deltaTime;
gpuCompute.compute();
renderer.render( scene, camera );
};
matrixRenderer.resize = (width, height) => {
if (width > height) {
mesh.material.uniforms.resolution.value.set(2, 2 * width / height);
} else {
mesh.material.uniforms.resolution.value.set(2 * height / width, 2);
}
};
return matrixRenderer;
};

View File

@@ -1,63 +0,0 @@
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.RenderPass = function ( scene, camera, overrideMaterial, clearColor, clearAlpha ) {
THREE.Pass.call( this );
this.scene = scene;
this.camera = camera;
this.overrideMaterial = overrideMaterial;
this.clearColor = clearColor;
this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 0;
this.clear = true;
this.clearDepth = false;
this.needsSwap = false;
};
THREE.RenderPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.RenderPass,
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
var oldAutoClear = renderer.autoClear;
renderer.autoClear = false;
this.scene.overrideMaterial = this.overrideMaterial;
var oldClearColor, oldClearAlpha;
if ( this.clearColor ) {
oldClearColor = renderer.getClearColor().getHex();
oldClearAlpha = renderer.getClearAlpha();
renderer.setClearColor( this.clearColor, this.clearAlpha );
}
if ( this.clearDepth ) {
renderer.clearDepth();
}
renderer.render( this.scene, this.camera, this.renderToScreen ? null : readBuffer, this.clear );
if ( this.clearColor ) {
renderer.setClearColor( oldClearColor, oldClearAlpha );
}
this.scene.overrideMaterial = null;
renderer.autoClear = oldAutoClear;
}
} );

View File

@@ -1,67 +0,0 @@
/**
* @author alteredq / http://alteredqualia.com/
*/
THREE.ShaderPass = function ( shader, textureID ) {
THREE.Pass.call( this );
this.textureID = ( textureID !== undefined ) ? textureID : "tDiffuse";
if ( shader instanceof THREE.ShaderMaterial ) {
this.uniforms = shader.uniforms;
this.material = shader;
} else if ( shader ) {
this.uniforms = THREE.UniformsUtils.clone( shader.uniforms );
this.material = new THREE.ShaderMaterial( {
defines: Object.assign( {}, shader.defines ),
uniforms: this.uniforms,
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader
} );
}
this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
this.scene = new THREE.Scene();
this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
this.quad.frustumCulled = false; // Avoid getting clipped
this.scene.add( this.quad );
};
THREE.ShaderPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.ShaderPass,
render: function( renderer, writeBuffer, readBuffer, delta, maskActive ) {
if ( this.uniforms[ this.textureID ] ) {
this.uniforms[ this.textureID ].value = readBuffer.texture;
}
this.quad.material = this.material;
if ( this.renderToScreen ) {
renderer.render( this.scene, this.camera );
} else {
renderer.render( this.scene, this.camera, writeBuffer, this.clear );
}
}
} );

View File

@@ -1,384 +0,0 @@
/**
* @author spidersharma / http://eduperiment.com/
*
* Inspired from Unreal Engine
* https://docs.unrealengine.com/latest/INT/Engine/Rendering/PostProcessEffects/Bloom/
*/
THREE.UnrealBloomPass = function ( resolution, strength, radius, threshold ) {
THREE.Pass.call( this );
this.strength = ( strength !== undefined ) ? strength : 1;
this.radius = radius;
this.threshold = threshold;
this.resolution = ( resolution !== undefined ) ? new THREE.Vector2( resolution.x, resolution.y ) : new THREE.Vector2( 256, 256 );
// create color only once here, reuse it later inside the render function
this.clearColor = new THREE.Color( 0, 0, 0 );
// render targets
var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat };
this.renderTargetsHorizontal = [];
this.renderTargetsVertical = [];
this.nMips = 5;
var resx = Math.round( this.resolution.x / 2 );
var resy = Math.round( this.resolution.y / 2 );
this.renderTargetBright = new THREE.WebGLRenderTarget( resx, resy, pars );
this.renderTargetBright.texture.name = "UnrealBloomPass.bright";
this.renderTargetBright.texture.generateMipmaps = false;
for ( var i = 0; i < this.nMips; i ++ ) {
var renderTarget = new THREE.WebGLRenderTarget( resx, resy, pars );
renderTarget.texture.name = "UnrealBloomPass.h" + i;
renderTarget.texture.generateMipmaps = false;
this.renderTargetsHorizontal.push( renderTarget );
var renderTarget = new THREE.WebGLRenderTarget( resx, resy, pars );
renderTarget.texture.name = "UnrealBloomPass.v" + i;
renderTarget.texture.generateMipmaps = false;
this.renderTargetsVertical.push( renderTarget );
resx = Math.round( resx / 2 );
resy = Math.round( resy / 2 );
}
// luminosity high pass material
if ( THREE.LuminosityHighPassShader === undefined )
console.error( "THREE.UnrealBloomPass relies on THREE.LuminosityHighPassShader" );
var highPassShader = THREE.LuminosityHighPassShader;
this.highPassUniforms = THREE.UniformsUtils.clone( highPassShader.uniforms );
this.highPassUniforms[ "luminosityThreshold" ].value = threshold;
this.highPassUniforms[ "smoothWidth" ].value = 0.01;
this.materialHighPassFilter = new THREE.ShaderMaterial( {
uniforms: this.highPassUniforms,
vertexShader: highPassShader.vertexShader,
fragmentShader: highPassShader.fragmentShader,
defines: {}
} );
// Gaussian Blur Materials
this.separableBlurMaterials = [];
var kernelSizeArray = [ 3, 5, 7, 9, 11 ];
var resx = Math.round( this.resolution.x / 2 );
var resy = Math.round( this.resolution.y / 2 );
for ( var i = 0; i < this.nMips; i ++ ) {
this.separableBlurMaterials.push( this.getSeperableBlurMaterial( kernelSizeArray[ i ] ) );
this.separableBlurMaterials[ i ].uniforms[ "texSize" ].value = new THREE.Vector2( resx, resy );
resx = Math.round( resx / 2 );
resy = Math.round( resy / 2 );
}
// Composite material
this.compositeMaterial = this.getCompositeMaterial( this.nMips );
this.compositeMaterial.uniforms[ "blurTexture1" ].value = this.renderTargetsVertical[ 0 ].texture;
this.compositeMaterial.uniforms[ "blurTexture2" ].value = this.renderTargetsVertical[ 1 ].texture;
this.compositeMaterial.uniforms[ "blurTexture3" ].value = this.renderTargetsVertical[ 2 ].texture;
this.compositeMaterial.uniforms[ "blurTexture4" ].value = this.renderTargetsVertical[ 3 ].texture;
this.compositeMaterial.uniforms[ "blurTexture5" ].value = this.renderTargetsVertical[ 4 ].texture;
this.compositeMaterial.uniforms[ "bloomStrength" ].value = strength;
this.compositeMaterial.uniforms[ "bloomRadius" ].value = 0.1;
this.compositeMaterial.needsUpdate = true;
var bloomFactors = [ 1.0, 0.8, 0.6, 0.4, 0.2 ];
this.compositeMaterial.uniforms[ "bloomFactors" ].value = bloomFactors;
this.bloomTintColors = [ new THREE.Vector3( 1, 1, 1 ), new THREE.Vector3( 1, 1, 1 ), new THREE.Vector3( 1, 1, 1 ),
new THREE.Vector3( 1, 1, 1 ), new THREE.Vector3( 1, 1, 1 ) ];
this.compositeMaterial.uniforms[ "bloomTintColors" ].value = this.bloomTintColors;
// copy material
if ( THREE.CopyShader === undefined ) {
console.error( "THREE.BloomPass relies on THREE.CopyShader" );
}
var copyShader = THREE.CopyShader;
this.copyUniforms = THREE.UniformsUtils.clone( copyShader.uniforms );
this.copyUniforms[ "opacity" ].value = 1.0;
this.materialCopy = new THREE.ShaderMaterial( {
uniforms: this.copyUniforms,
vertexShader: copyShader.vertexShader,
fragmentShader: copyShader.fragmentShader,
blending: THREE.AdditiveBlending,
depthTest: false,
depthWrite: false,
transparent: true
} );
this.enabled = true;
this.needsSwap = false;
this.oldClearColor = new THREE.Color();
this.oldClearAlpha = 1;
this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
this.scene = new THREE.Scene();
this.basic = new THREE.MeshBasicMaterial();
this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
this.quad.frustumCulled = false; // Avoid getting clipped
this.scene.add( this.quad );
};
THREE.UnrealBloomPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
constructor: THREE.UnrealBloomPass,
dispose: function () {
for ( var i = 0; i < this.renderTargetsHorizontal.length; i ++ ) {
this.renderTargetsHorizontal[ i ].dispose();
}
for ( var i = 0; i < this.renderTargetsVertical.length; i ++ ) {
this.renderTargetsVertical[ i ].dispose();
}
this.renderTargetBright.dispose();
},
setSize: function ( width, height ) {
var resx = Math.round( width / 2 );
var resy = Math.round( height / 2 );
this.renderTargetBright.setSize( resx, resy );
for ( var i = 0; i < this.nMips; i ++ ) {
this.renderTargetsHorizontal[ i ].setSize( resx, resy );
this.renderTargetsVertical[ i ].setSize( resx, resy );
this.separableBlurMaterials[ i ].uniforms[ "texSize" ].value = new THREE.Vector2( resx, resy );
resx = Math.round( resx / 2 );
resy = Math.round( resy / 2 );
}
},
render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
this.oldClearColor.copy( renderer.getClearColor() );
this.oldClearAlpha = renderer.getClearAlpha();
var oldAutoClear = renderer.autoClear;
renderer.autoClear = false;
renderer.setClearColor( this.clearColor, 0 );
if ( maskActive ) renderer.context.disable( renderer.context.STENCIL_TEST );
// Render input to screen
if ( this.renderToScreen ) {
this.quad.material = this.basic;
this.basic.map = readBuffer.texture;
renderer.render( this.scene, this.camera, undefined, true );
}
// 1. Extract Bright Areas
this.highPassUniforms[ "tDiffuse" ].value = readBuffer.texture;
this.highPassUniforms[ "luminosityThreshold" ].value = this.threshold;
this.quad.material = this.materialHighPassFilter;
renderer.render( this.scene, this.camera, this.renderTargetBright, true );
// 2. Blur All the mips progressively
var inputRenderTarget = this.renderTargetBright;
for ( var i = 0; i < this.nMips; i ++ ) {
this.quad.material = this.separableBlurMaterials[ i ];
this.separableBlurMaterials[ i ].uniforms[ "colorTexture" ].value = inputRenderTarget.texture;
this.separableBlurMaterials[ i ].uniforms[ "direction" ].value = THREE.UnrealBloomPass.BlurDirectionX;
renderer.render( this.scene, this.camera, this.renderTargetsHorizontal[ i ], true );
this.separableBlurMaterials[ i ].uniforms[ "colorTexture" ].value = this.renderTargetsHorizontal[ i ].texture;
this.separableBlurMaterials[ i ].uniforms[ "direction" ].value = THREE.UnrealBloomPass.BlurDirectionY;
renderer.render( this.scene, this.camera, this.renderTargetsVertical[ i ], true );
inputRenderTarget = this.renderTargetsVertical[ i ];
}
// Composite All the mips
this.quad.material = this.compositeMaterial;
this.compositeMaterial.uniforms[ "bloomStrength" ].value = this.strength;
this.compositeMaterial.uniforms[ "bloomRadius" ].value = this.radius;
this.compositeMaterial.uniforms[ "bloomTintColors" ].value = this.bloomTintColors;
renderer.render( this.scene, this.camera, this.renderTargetsHorizontal[ 0 ], true );
// Blend it additively over the input texture
this.quad.material = this.materialCopy;
this.copyUniforms[ "tDiffuse" ].value = this.renderTargetsHorizontal[ 0 ].texture;
if ( maskActive ) renderer.context.enable( renderer.context.STENCIL_TEST );
if ( this.renderToScreen ) {
renderer.render( this.scene, this.camera, undefined, false );
} else {
renderer.render( this.scene, this.camera, readBuffer, false );
}
// Restore renderer settings
renderer.setClearColor( this.oldClearColor, this.oldClearAlpha );
renderer.autoClear = oldAutoClear;
},
getSeperableBlurMaterial: function ( kernelRadius ) {
return new THREE.ShaderMaterial( {
defines: {
"KERNEL_RADIUS": kernelRadius,
"SIGMA": kernelRadius
},
uniforms: {
"colorTexture": { value: null },
"texSize": { value: new THREE.Vector2( 0.5, 0.5 ) },
"direction": { value: new THREE.Vector2( 0.5, 0.5 ) }
},
vertexShader:
"varying vec2 vUv;\n\
void main() {\n\
vUv = uv;\n\
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
}",
fragmentShader:
"#include <common>\
varying vec2 vUv;\n\
uniform sampler2D colorTexture;\n\
uniform vec2 texSize;\
uniform vec2 direction;\
\
float gaussianPdf(in float x, in float sigma) {\
return 0.39894 * exp( -0.5 * x * x/( sigma * sigma))/sigma;\
}\
void main() {\n\
vec2 invSize = 1.0 / texSize;\
float fSigma = float(SIGMA);\
float weightSum = gaussianPdf(0.0, fSigma);\
vec3 diffuseSum = texture2D( colorTexture, vUv).rgb * weightSum;\
for( int i = 1; i < KERNEL_RADIUS; i ++ ) {\
float x = float(i);\
float w = gaussianPdf(x, fSigma);\
vec2 uvOffset = direction * invSize * x;\
vec3 sample1 = texture2D( colorTexture, vUv + uvOffset).rgb;\
vec3 sample2 = texture2D( colorTexture, vUv - uvOffset).rgb;\
diffuseSum += (sample1 + sample2) * w;\
weightSum += 2.0 * w;\
}\
gl_FragColor = vec4(diffuseSum/weightSum, 1.0);\n\
}"
} );
},
getCompositeMaterial: function ( nMips ) {
return new THREE.ShaderMaterial( {
defines: {
"NUM_MIPS": nMips
},
uniforms: {
"blurTexture1": { value: null },
"blurTexture2": { value: null },
"blurTexture3": { value: null },
"blurTexture4": { value: null },
"blurTexture5": { value: null },
"dirtTexture": { value: null },
"bloomStrength": { value: 1.0 },
"bloomFactors": { value: null },
"bloomTintColors": { value: null },
"bloomRadius": { value: 0.0 }
},
vertexShader:
"varying vec2 vUv;\n\
void main() {\n\
vUv = uv;\n\
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
}",
fragmentShader:
"varying vec2 vUv;\
uniform sampler2D blurTexture1;\
uniform sampler2D blurTexture2;\
uniform sampler2D blurTexture3;\
uniform sampler2D blurTexture4;\
uniform sampler2D blurTexture5;\
uniform sampler2D dirtTexture;\
uniform float bloomStrength;\
uniform float bloomRadius;\
uniform float bloomFactors[NUM_MIPS];\
uniform vec3 bloomTintColors[NUM_MIPS];\
\
float lerpBloomFactor(const in float factor) { \
float mirrorFactor = 1.2 - factor;\
return mix(factor, mirrorFactor, bloomRadius);\
}\
\
void main() {\
gl_FragColor = bloomStrength * ( lerpBloomFactor(bloomFactors[0]) * vec4(bloomTintColors[0], 1.0) * texture2D(blurTexture1, vUv) + \
lerpBloomFactor(bloomFactors[1]) * vec4(bloomTintColors[1], 1.0) * texture2D(blurTexture2, vUv) + \
lerpBloomFactor(bloomFactors[2]) * vec4(bloomTintColors[2], 1.0) * texture2D(blurTexture3, vUv) + \
lerpBloomFactor(bloomFactors[3]) * vec4(bloomTintColors[3], 1.0) * texture2D(blurTexture4, vUv) + \
lerpBloomFactor(bloomFactors[4]) * vec4(bloomTintColors[4], 1.0) * texture2D(blurTexture5, vUv) );\
}"
} );
}
} );
THREE.UnrealBloomPass.BlurDirectionX = new THREE.Vector2( 1.0, 0.0 );
THREE.UnrealBloomPass.BlurDirectionY = new THREE.Vector2( 0.0, 1.0 );

140
js/bloomPass.js Normal file
View File

@@ -0,0 +1,140 @@
import { makePassFBO, makePyramid, resizePyramid } from "./utils.js";
const pyramidHeight = 5;
const levelStrengths = Array(pyramidHeight)
.fill()
.map((_, index) =>
Math.pow(index / (pyramidHeight * 2) + 0.5, 1 / 3).toPrecision(5)
)
.reverse();
export default (regl, config, input) => {
if (config.effect === "none") {
return {
fbo: input,
resize: () => {},
render: () => {}
};
}
const highPassPyramid = makePyramid(regl, pyramidHeight);
const horizontalBlurPyramid = makePyramid(regl, pyramidHeight);
const verticalBlurPyramid = makePyramid(regl, pyramidHeight);
const fbo = makePassFBO(regl);
const highPass = regl({
frag: `
precision mediump float;
varying vec2 vUV;
uniform sampler2D tex;
uniform float highPassThreshold;
void main() {
float value = texture2D(tex, vUV).r;
if (value < highPassThreshold) {
value = 0.;
}
gl_FragColor = vec4(vec3(value), 1.0);
}
`,
uniforms: {
tex: regl.prop("tex")
},
framebuffer: regl.prop("fbo")
});
const blur = regl({
frag: `
precision mediump float;
varying vec2 vUV;
uniform sampler2D tex;
uniform vec2 direction;
uniform float width, height;
void main() {
vec2 size = width > height ? vec2(width / height, 1.) : vec2(1., height / width);
gl_FragColor =
texture2D(tex, vUV) * 0.442 +
(
texture2D(tex, vUV + direction / max(width, height) * size) +
texture2D(tex, vUV - direction / max(width, height) * size)
) * 0.279;
}
`,
uniforms: {
tex: regl.prop("tex"),
direction: regl.prop("direction"),
height: regl.context("viewportWidth"),
width: regl.context("viewportHeight")
},
framebuffer: regl.prop("fbo")
});
const combineBloom = regl({
frag: `
precision mediump float;
varying vec2 vUV;
${verticalBlurPyramid
.map((_, index) => `uniform sampler2D tex_${index};`)
.join("\n")}
uniform sampler2D tex;
uniform float bloomStrength;
void main() {
vec4 total = vec4(0.);
${verticalBlurPyramid
.map(
(_, index) =>
`total += texture2D(tex_${index}, vUV) * ${levelStrengths[index]};`
)
.join("\n")}
gl_FragColor = total * bloomStrength + texture2D(tex, vUV);
}
`,
uniforms: Object.assign(
{
tex: input
},
Object.fromEntries(
verticalBlurPyramid.map((fbo, index) => [`tex_${index}`, fbo])
)
),
framebuffer: fbo
});
return {
fbo,
resize: (viewportWidth, viewportHeight) => {
resizePyramid(
highPassPyramid,
viewportWidth,
viewportHeight,
config.bloomSize
);
resizePyramid(
horizontalBlurPyramid,
viewportWidth,
viewportHeight,
config.bloomSize
);
resizePyramid(
verticalBlurPyramid,
viewportWidth,
viewportHeight,
config.bloomSize
);
fbo.resize(viewportWidth, viewportHeight);
},
render: () => {
highPassPyramid.forEach(fbo => highPass({ fbo, tex: input }));
horizontalBlurPyramid.forEach((fbo, index) =>
blur({ fbo, tex: highPassPyramid[index], direction: [1, 0] })
);
verticalBlurPyramid.forEach((fbo, index) =>
blur({
fbo,
tex: horizontalBlurPyramid[index],
direction: [0, 1]
})
);
combineBloom();
}
};
};

118
js/colorPass.js Normal file
View File

@@ -0,0 +1,118 @@
import { makePassFBO } from "./utils.js";
const colorizeByPalette = regl =>
regl({
frag: `
precision mediump float;
#define PI 3.14159265359
uniform sampler2D tex;
uniform sampler2D paletteColorData;
uniform float ditherMagnitude;
uniform float time;
varying vec2 vUV;
highp float rand( const in vec2 uv, const in float t ) {
const highp float a = 12.9898, b = 78.233, c = 43758.5453;
highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );
return fract(sin(sn) * c + t);
}
void main() {
gl_FragColor = texture2D( paletteColorData, vec2( texture2D( tex, vUV ).r - rand( gl_FragCoord.xy, time ) * ditherMagnitude, 0.0 ) );
}
`,
uniforms: {
ditherMagnitude: 0.05
}
});
const colorizeByStripes = regl =>
regl({
frag: `
precision mediump float;
#define PI 3.14159265359
uniform sampler2D tex;
uniform sampler2D stripeColorData;
uniform float ditherMagnitude;
varying vec2 vUV;
highp float rand( const in vec2 uv ) {
const highp float a = 12.9898, b = 78.233, c = 43758.5453;
highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );
return fract(sin(sn) * c);
}
void main() {
float value = texture2D(tex, vUV).r;
vec3 value2 = texture2D(stripeColorData, vUV).rgb - rand( gl_FragCoord.xy ) * ditherMagnitude;
gl_FragColor = vec4(value2 * value, 1.0);
}
`,
uniforms: {
ditherMagnitude: 0.1
}
});
const colorizeByImage = regl =>
regl({
frag: `
precision mediump float;
uniform sampler2D tex;
uniform sampler2D backgroundTex;
varying vec2 vUV;
void main() {
gl_FragColor = vec4(texture2D(backgroundTex, vUV).rgb * (pow(texture2D(tex, vUV).r, 1.5) * 0.995 + 0.005), 1.0);
}
`,
uniforms: {
backgroundTex: regl.prop("backgroundTex")
}
});
const colorizersByEffect = {
plain: colorizeByPalette,
customStripes: colorizeByStripes,
stripes: colorizeByStripes,
image: colorizeByImage
};
export default (regl, config, inputFBO) => {
const fbo = makePassFBO(regl);
if (config.effect === "none") {
return {
fbo: inputFBO,
resize: () => {},
render: () => {}
};
}
const colorize = regl({
uniforms: {
tex: regl.prop("tex")
},
framebuffer: fbo
});
const colorizer = (config.effect in colorizersByEffect
? colorizersByEffect[config.effect]
: colorizeByPalette)(regl);
return {
fbo,
resize: fbo.resize,
render: resources => {
colorize(
{
tex: inputFBO
},
() => colorizer(resources)
);
}
};
};

307
js/config.js Normal file
View File

@@ -0,0 +1,307 @@
const fonts = {
coptic: {
glyphTexURL: "coptic_msdf.png",
glyphSequenceLength: 32,
numFontColumns: 8
},
gothic: {
glyphTexURL: "gothic_msdf.png",
glyphSequenceLength: 27,
numFontColumns: 8
},
matrixcode: {
glyphTexURL: "matrixcode_msdf.png",
glyphSequenceLength: 57,
numFontColumns: 8
}
};
const versions = {
paradise: {
...fonts.coptic,
bloomRadius: 1.15,
bloomStrength: 1.75,
highPassThreshold: 0,
cycleSpeed: 0.05,
cycleStyleName: "cycleFasterWhenDimmed",
cursorEffectThreshold: 1,
brightnessOffset: 0.0,
brightnessMultiplier: 1.0,
fallSpeed: 0.05,
glyphEdgeCrop: 0.0,
glyphHeightToWidth: 1,
hasSun: true,
hasThunder: false,
isPolar: true,
rippleTypeName: "circle",
rippleThickness: 0.2,
rippleScale: 30,
rippleSpeed: 0.2,
numColumns: 30,
palette: [
{ rgb: [0.0, 0.0, 0.0], at: 0.0 },
{ rgb: [0.52, 0.17, 0.05], at: 0.4 },
{ rgb: [0.82, 0.37, 0.12], at: 0.7 },
{ rgb: [1.0, 0.74, 0.29], at: 0.9 },
{ rgb: [1.0, 0.9, 0.8], at: 1.0 }
],
raindropLength: 0.5,
slant: 0
},
nightmare: {
...fonts.gothic,
bloomRadius: 0.8,
bloomStrength: 1,
highPassThreshold: 0.5,
cycleSpeed: 0.02,
cycleStyleName: "cycleFasterWhenDimmed",
cursorEffectThreshold: 1,
brightnessOffset: 0.0,
brightnessMultiplier: 1.0,
fallSpeed: 2.0,
glyphEdgeCrop: 0.0,
glyphHeightToWidth: 1,
hasSun: false,
hasThunder: true,
isPolar: false,
rippleTypeName: null,
rippleThickness: 0.2,
rippleScale: 30,
rippleSpeed: 0.2,
numColumns: 60,
palette: [
{ rgb: [0.0, 0.0, 0.0], at: 0.0 },
{ rgb: [0.52, 0.0, 0.0], at: 0.2 },
{ rgb: [0.82, 0.05, 0.05], at: 0.4 },
{ rgb: [1.0, 0.6, 0.3], at: 0.8 },
{ rgb: [1.0, 1.0, 0.9], at: 1.0 }
],
raindropLength: 0.6,
slant: 360 / 16
},
classic: {
...fonts.matrixcode,
bloomRadius: 0.5,
bloomStrength: 1,
highPassThreshold: 0.3,
cycleSpeed: 1,
cycleStyleName: "cycleFasterWhenDimmed",
cursorEffectThreshold: 1,
brightnessOffset: 0.0,
brightnessMultiplier: 1.0,
fallSpeed: 1,
glyphEdgeCrop: 0.0,
glyphHeightToWidth: 1,
hasSun: false,
hasThunder: false,
isPolar: false,
rippleTypeName: null,
rippleThickness: 0.2,
rippleScale: 30,
rippleSpeed: 0.2,
numColumns: 80,
palette: [
{ rgb: [0 / 255, 0 / 255, 0 / 255], at: 0 / 16 },
{ rgb: [6 / 255, 16 / 255, 8 / 255], at: 1 / 16 },
{ rgb: [11 / 255, 28 / 255, 15 / 255], at: 2 / 16 },
{ rgb: [17 / 255, 41 / 255, 23 / 255], at: 3 / 16 },
{ rgb: [20 / 255, 58 / 255, 31 / 255], at: 4 / 16 },
{ rgb: [23 / 255, 84 / 255, 39 / 255], at: 5 / 16 },
{ rgb: [30 / 255, 113 / 255, 48 / 255], at: 6 / 16 },
{ rgb: [43 / 255, 142 / 255, 60 / 255], at: 7 / 16 },
{ rgb: [57 / 255, 160 / 255, 72 / 255], at: 8 / 16 },
{ rgb: [70 / 255, 175 / 255, 81 / 255], at: 9 / 16 },
{ rgb: [75 / 255, 187 / 255, 85 / 255], at: 10 / 16 },
{ rgb: [78 / 255, 196 / 255, 91 / 255], at: 11 / 16 },
{ rgb: [83 / 255, 203 / 255, 102 / 255], at: 12 / 16 },
{ rgb: [92 / 255, 212 / 255, 114 / 255], at: 13 / 16 },
{ rgb: [109 / 255, 223 / 255, 130 / 255], at: 14 / 16 },
{ rgb: [129 / 255, 232 / 255, 148 / 255], at: 15 / 16 },
{ rgb: [140 / 255, 235 / 255, 157 / 255], at: 16 / 16 }
],
raindropLength: 1,
slant: 0
},
operator: {
...fonts.matrixcode,
bloomRadius: 0.3,
bloomStrength: 0.75,
highPassThreshold: 0.0,
cycleSpeed: 0.05,
cycleStyleName: "cycleRandomly",
cursorEffectThreshold: 0.466,
brightnessOffset: 0.25,
brightnessMultiplier: 0.0,
fallSpeed: 0.6,
glyphEdgeCrop: 0.15,
glyphHeightToWidth: 1.35,
hasSun: false,
hasThunder: false,
isPolar: false,
rippleTypeName: "box",
rippleThickness: 0.2,
rippleScale: 30,
rippleSpeed: 0.2,
numColumns: 108,
palette: [
{ rgb: [0.0, 0.0, 0.0], at: 0.0 },
{ rgb: [0.18, 0.9, 0.35], at: 0.6 },
{ rgb: [0.9, 1.0, 0.9], at: 1.0 }
],
raindropLength: 1.5,
slant: 0
}
};
versions.throwback = versions.operator;
versions["1999"] = versions.classic;
export default (searchString, makePaletteTexture) => {
const urlParams = new URLSearchParams(searchString);
const getParam = (keyOrKeys, defaultValue) => {
if (Array.isArray(keyOrKeys)) {
const keys = keyOrKeys;
const key = keys.find(key => urlParams.has(key));
return key != null ? urlParams.get(key) : defaultValue;
} else {
const key = keyOrKeys;
return urlParams.has(key) ? urlParams.get(key) : defaultValue;
}
};
const versionName = getParam("version", "classic");
const version =
versions[versionName] == null ? versions.classic : versions[versionName];
const config = { ...version };
config.animationSpeed = parseFloat(getParam("animationSpeed", 1));
config.fallSpeed *= parseFloat(getParam("fallSpeed", 1));
config.cycleSpeed *= parseFloat(getParam("cycleSpeed", 1));
config.numColumns = parseInt(getParam("width", config.numColumns));
config.raindropLength = parseFloat(
getParam(["raindropLength", "dropLength"], config.raindropLength)
);
config.glyphSequenceLength = config.glyphSequenceLength;
config.slant =
(parseFloat(getParam(["slant", "angle"], config.slant)) * Math.PI) / 180;
config.slantVec = [Math.cos(config.slant), Math.sin(config.slant)];
config.slantScale =
1 / (Math.abs(Math.sin(2 * config.slant)) * (Math.sqrt(2) - 1) + 1);
config.glyphEdgeCrop = parseFloat(getParam("encroach", config.glyphEdgeCrop));
config.glyphHeightToWidth = parseFloat(
getParam("stretch", config.glyphHeightToWidth)
);
config.cursorEffectThreshold = getParam(
"cursorEffectThreshold",
config.cursorEffectThreshold
);
config.bloomSize = Math.max(
0.01,
Math.min(1, parseFloat(getParam("bloomSize", 0.5)))
);
config.effect = getParam("effect", "plain");
config.brightnessChangeBias =
config.animationSpeed * config.fallSpeed == 0
? 1
: Math.min(1, Math.abs(config.animationSpeed * config.fallSpeed));
config.backgroundImage = getParam(
"url",
"https://upload.wikimedia.org/wikipedia/commons/0/0a/Flammarion_Colored.jpg"
);
config.customStripes = getParam(
"colors",
"0.4,0.15,0.1,0.4,0.15,0.1,0.8,0.8,0.6,0.8,0.8,0.6,1.0,0.7,0.8,1.0,0.7,0.8,"
)
.split(",")
.map(parseFloat);
config.showComputationTexture = config.effect === "none";
switch (config.cycleStyleName) {
case "cycleFasterWhenDimmed":
config.cycleStyle = 0;
break;
case "cycleRandomly":
default:
config.cycleStyle = 1;
break;
}
switch (config.rippleTypeName) {
case "box":
config.rippleType = 0;
break;
case "circle":
config.rippleType = 1;
break;
default:
config.rippleType = -1;
}
const PALETTE_SIZE = 2048;
const paletteColors = Array(PALETTE_SIZE);
const sortedEntries = version.palette
.slice()
.sort((e1, e2) => e1.at - e2.at)
.map(entry => ({
rgb: entry.rgb,
arrayIndex: Math.floor(
Math.max(Math.min(1, entry.at), 0) * (PALETTE_SIZE - 1)
)
}));
sortedEntries.unshift({ rgb: sortedEntries[0].rgb, arrayIndex: 0 });
sortedEntries.push({
rgb: sortedEntries[sortedEntries.length - 1].rgb,
arrayIndex: PALETTE_SIZE - 1
});
sortedEntries.forEach((entry, index) => {
paletteColors[entry.arrayIndex] = entry.rgb.slice();
if (index + 1 < sortedEntries.length) {
const nextEntry = sortedEntries[index + 1];
const diff = nextEntry.arrayIndex - entry.arrayIndex;
for (let i = 0; i < diff; i++) {
const ratio = i / diff;
paletteColors[entry.arrayIndex + i] = [
entry.rgb[0] * (1 - ratio) + nextEntry.rgb[0] * ratio,
entry.rgb[1] * (1 - ratio) + nextEntry.rgb[1] * ratio,
entry.rgb[2] * (1 - ratio) + nextEntry.rgb[2] * ratio
];
}
}
});
config.paletteColorData = makePaletteTexture(
paletteColors.flat().map(i => i * 0xff)
);
let stripeColors = [0, 0, 0];
if (config.effect === "pride") {
config.effect = "stripes";
config.customStripes = [
[1, 0, 0],
[1, 0.5, 0],
[1, 1, 0],
[0, 1, 0],
[0, 0, 1],
[0.8, 0, 1]
].flat();
}
if (config.effect === "customStripes" || config.effect === "stripes") {
const numFlagColors = Math.floor(config.customStripes.length / 3);
stripeColors = config.customStripes.slice(0, numFlagColors * 3);
}
config.stripeColorData = makePaletteTexture(
stripeColors.map(f => Math.floor(f * 0xff))
);
const uniforms = Object.fromEntries(
Object.entries(config).filter(([key, value]) => {
const type = typeof (Array.isArray(value) ? value[0] : value);
return type !== "string" && type !== "object";
})
);
return [config, uniforms];
};

300
js/renderer.js Normal file
View File

@@ -0,0 +1,300 @@
import { makePassFBO } from "./utils.js";
export default (regl, config) => {
const state = Array(2)
.fill()
.map(() =>
regl.framebuffer({
color: regl.texture({
radius: config.numColumns,
wrapT: "clamp",
type: "half float"
}),
depthStencil: false
})
);
const fbo = makePassFBO(regl);
const update = regl({
frag: `
precision highp float;
#define PI 3.14159265359
#define SQRT_2 1.4142135623730951
#define SQRT_5 2.23606797749979
uniform float numColumns;
uniform sampler2D lastState;
uniform bool hasSun;
uniform bool hasThunder;
uniform bool showComputationTexture;
uniform float brightnessChangeBias;
uniform float brightnessMultiplier;
uniform float brightnessOffset;
uniform float cursorEffectThreshold;
uniform float time;
uniform float animationSpeed;
uniform float cycleSpeed;
uniform float fallSpeed;
uniform float raindropLength;
uniform float glyphHeightToWidth;
uniform float glyphSequenceLength;
uniform float numFontColumns;
uniform int cycleStyle;
uniform float rippleScale;
uniform float rippleSpeed;
uniform float rippleThickness;
uniform int rippleType;
float max2(vec2 v) {
return max(v.x, v.y);
}
highp float rand( const in vec2 uv ) {
const highp float a = 12.9898, b = 78.233, c = 43758.5453;
highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );
return fract(sin(sn) * c);
}
vec2 rand2(vec2 p) {
return fract(vec2(sin(p.x * 591.32 + p.y * 154.077), cos(p.x * 391.32 + p.y * 49.077)));
}
highp float blast( const in float x, const in float power ) {
return pow(pow(pow(x, power), power), power);
}
float ripple(vec2 uv, float simTime) {
if (rippleType == -1) {
return 0.;
}
float rippleTime = (simTime * 0.5 + 0.2 * sin(simTime)) * rippleSpeed + 1.;
vec2 offset = rand2(vec2(floor(rippleTime), 0.)) - 0.5;
vec2 ripplePos = uv + offset;
float rippleDistance;
if (rippleType == 0) {
rippleDistance = max2(abs(ripplePos) * vec2(1.0, glyphHeightToWidth));
} else if (rippleType == 1) {
rippleDistance = length(ripplePos);
}
float rippleValue = fract(rippleTime) * rippleScale - rippleDistance;
if (rippleValue > 0. && rippleValue < rippleThickness) {
return 0.75;
} else {
return 0.;
}
}
void main() {
vec2 uv = gl_FragCoord.xy / numColumns;
float columnTimeOffset = rand(vec2(gl_FragCoord.x, 0.0));
float columnSpeedOffset = rand(vec2(gl_FragCoord.x + 0.1, 0.0));
vec4 data = texture2D( lastState, uv );
bool isInitializing = length(data) == 0.;
if (isInitializing) {
data = vec4(
rand(uv),
showComputationTexture ? 0.5 : rand(uv),
0.,
0.
);
}
float brightness = data.r;
float glyphCycle = data.g;
float simTime = time * animationSpeed;
float columnTime = (columnTimeOffset * 1000.0 + simTime * 0.5 * fallSpeed) * (0.5 + columnSpeedOffset * 0.5) + (sin(simTime * fallSpeed * columnSpeedOffset) * 0.2);
float glyphTime = (gl_FragCoord.y * 0.01 + columnTime) / raindropLength;
float value = 1.0 - fract((glyphTime + 0.3 * sin(SQRT_2 * glyphTime) + 0.2 * sin(SQRT_5 * glyphTime)));
float newBrightness = 3.0 * log(value * 1.25);
if (hasSun) {
newBrightness = pow(fract(newBrightness * 0.5), 3.0) * uv.y * 2.0;
}
if (hasThunder) {
vec2 distVec = (gl_FragCoord.xy / numColumns - vec2(0.5, 1.0)) * vec2(1.0, 2.0);
float thunder = (blast(sin(SQRT_5 * simTime), 10.0) + blast(sin(SQRT_2 * simTime), 10.0));
thunder *= 30.0 * (1.0 - 1.0 * length(distVec));
newBrightness *= max(0.0, thunder) * 1.0 + 0.7;
if (newBrightness > brightness) {
brightness = newBrightness;
} else {
brightness = mix(brightness, newBrightness, brightnessChangeBias * 0.1);
}
} else if (isInitializing) {
brightness = newBrightness;
} else {
brightness = mix(brightness, newBrightness, brightnessChangeBias);
}
float glyphCycleSpeed = 0.0;
if (cycleStyle == 1) {
glyphCycleSpeed = fract((glyphTime + 0.7 * sin(SQRT_2 * glyphTime) + 1.1 * sin(SQRT_5 * glyphTime))) * 0.75;
} else if (cycleStyle == 0) {
if (brightness > 0.0) glyphCycleSpeed = pow(1.0 - brightness, 4.0);
}
glyphCycle = fract(glyphCycle + 0.005 * animationSpeed * cycleSpeed * glyphCycleSpeed);
float symbol = floor(glyphSequenceLength * glyphCycle);
float symbolX = mod(symbol, numFontColumns);
float symbolY = ((numFontColumns - 1.0) - (symbol - symbolX) / numFontColumns);
float effect = 0.;
effect += ripple(gl_FragCoord.xy / numColumns * 2.0 - 1.0, simTime);
if (brightness >= cursorEffectThreshold) {
effect = 1.0;
}
if (brightness > -1.) {
brightness = brightness * brightnessMultiplier + brightnessOffset;
}
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
gl_FragColor.r = brightness;
gl_FragColor.g = glyphCycle;
if (showComputationTexture) {
// Better use of the blue channel, for show and tell
gl_FragColor.b = min(1.0, glyphCycleSpeed);
gl_FragColor.a = 1.0;
} else {
gl_FragColor.b = symbolY * numFontColumns + symbolX;
gl_FragColor.a = effect;
}
}
`,
uniforms: {
lastState: ({ tick }) => state[tick % 2]
},
framebuffer: ({ tick }) => state[(tick + 1) % 2]
});
const render = regl({
vert: `
attribute vec2 aPosition;
uniform float width;
uniform float height;
varying vec2 vUV;
void main() {
vUV = aPosition / 2.0 + 0.5;
vec2 size = width > height ? vec2(width / height, 1.) : vec2(1., height / width);
gl_Position = vec4( size * aPosition, 0.0, 1.0 );
}
`,
frag: `
#define PI 3.14159265359
#ifdef GL_OES_standard_derivatives
#extension GL_OES_standard_derivatives: enable
#endif
precision lowp float;
uniform sampler2D msdfTex;
uniform sampler2D lastState;
uniform float numColumns;
uniform float numFontColumns;
uniform vec2 slantVec;
uniform float slantScale;
uniform float glyphHeightToWidth;
uniform float glyphEdgeCrop;
uniform bool isPolar;
uniform bool showComputationTexture;
varying vec2 vUV;
float median3(vec3 i) {
return max(min(i.r, i.g), min(max(i.r, i.g), i.b));
}
void main() {
vec2 uv = vUV;
if (isPolar) {
uv -= 0.5;
uv *= 0.5;
uv.y -= 0.5;
float radius = length(uv);
float angle = atan(uv.y, uv.x) / (2. * PI) + 0.5;
uv = vec2(angle * 4. - 0.5, 1.25 - radius * 1.5);
} else {
uv = vec2(
(uv.x - 0.5) * slantVec.x + (uv.y - 0.5) * slantVec.y,
(uv.y - 0.5) * slantVec.x - (uv.x - 0.5) * slantVec.y
) * slantScale + 0.5;
}
uv.y /= glyphHeightToWidth;
vec4 glyph = texture2D(lastState, uv);
if (showComputationTexture) {
gl_FragColor = glyph;
return;
}
// Unpack the values from the font texture
float brightness = glyph.r;
float effect = glyph.a;
brightness = max(effect, brightness);
float symbolIndex = glyph.b;
vec2 symbolUV = vec2(mod(symbolIndex, numFontColumns), floor(symbolIndex / numFontColumns));
vec2 glyphUV = fract(uv * numColumns);
glyphUV -= 0.5;
glyphUV *= clamp(1.0 - glyphEdgeCrop, 0.0, 1.0);
glyphUV += 0.5;
vec3 dist = texture2D(msdfTex, (glyphUV + symbolUV) / numFontColumns).rgb;
// The rest is straight up MSDF
float sigDist = median3(dist) - 0.5;
float alpha = clamp(sigDist/fwidth(sigDist) + 0.5, 0.0, 1.0);
gl_FragColor = vec4(vec3(brightness * alpha), 1.0);
}
`,
uniforms: {
msdfTex: regl.prop("msdfTex"),
height: regl.context("viewportWidth"),
width: regl.context("viewportHeight"),
lastState: ({ tick }) => state[tick % 2]
},
framebuffer: fbo
});
return {
resize: fbo.resize,
fbo,
update,
render
};
};

91
js/utils.js Normal file
View File

@@ -0,0 +1,91 @@
const makePassTexture = regl =>
regl.texture({
width: 1,
height: 1,
type: "half float",
wrap: "clamp",
min: "linear",
mag: "linear"
});
const makePassFBO = regl => regl.framebuffer({ color: makePassTexture(regl) });
const makePyramid = (regl, height) =>
Array(height)
.fill()
.map(_ => makePassFBO(regl));
const resizePyramid = (pyramid, vw, vh, scale) =>
pyramid.forEach((fbo, index) =>
fbo.resize(
Math.floor((vw * scale) / 2 ** index),
Math.floor((vh * scale) / 2 ** index)
)
);
const loadImages = async (regl, manifest) => {
const keys = Object.keys(manifest);
const urls = Object.values(manifest);
const images = await Promise.all(urls.map(url => loadImage(regl, url)));
return Object.fromEntries(images.map((image, index) => [keys[index], image]));
};
const loadImage = async (regl, url) => {
if (url == null) {
return null;
}
const image = new Image();
image.crossOrigin = "anonymous";
image.src = url;
await image.decode();
return regl.texture({
data: image,
mag: "linear",
min: "linear",
flipY: true
});
};
const makeFullScreenQuad = (regl, uniforms) =>
regl({
vert: `
precision mediump float;
attribute vec2 aPosition;
varying vec2 vUV;
void main() {
vUV = 0.5 * (aPosition + 1.0);
gl_Position = vec4(aPosition, 0, 1);
}
`,
frag: `
precision mediump float;
varying vec2 vUV;
uniform sampler2D tex;
void main() {
gl_FragColor = texture2D(tex, vUV);
}
`,
attributes: {
aPosition: [-4, -4, 4, -4, 0, 4]
},
uniforms: {
...uniforms,
time: regl.context("time")
},
depth: { enable: false },
count: 3
});
export {
makePassTexture,
makePassFBO,
makePyramid,
resizePyramid,
loadImage,
loadImages,
makeFullScreenQuad
};

9669
lib/regl.js Normal file

File diff suppressed because it is too large Load Diff

151
lib/regl.min.js vendored Normal file
View File

@@ -0,0 +1,151 @@
(function(aa,ia){"object"===typeof exports&&"undefined"!==typeof module?module.exports=ia():"function"===typeof define&&define.amd?define(ia):aa.createREGL=ia()})(this,function(){function aa(a,b){this.id=Ab++;this.type=a;this.data=b}function ia(a){if(0===a.length)return[];var b=a.charAt(0),c=a.charAt(a.length-1);if(1<a.length&&b===c&&('"'===b||"'"===b))return['"'+a.substr(1,a.length-2).replace(/\\/g,"\\\\").replace(/"/g,'\\"')+'"'];if(b=/\[(false|true|null|\d+|'[^']*'|"[^"]*")\]/.exec(a))return ia(a.substr(0,
b.index)).concat(ia(b[1])).concat(ia(a.substr(b.index+b[0].length)));b=a.split(".");if(1===b.length)return['"'+a.replace(/\\/g,"\\\\").replace(/"/g,'\\"')+'"'];a=[];for(c=0;c<b.length;++c)a=a.concat(ia(b[c]));return a}function Za(a){return"["+ia(a).join("][")+"]"}function Bb(){var a={"":0},b=[""];return{id:function(c){var e=a[c];if(e)return e;e=a[c]=b.length;b.push(c);return e},str:function(a){return b[a]}}}function Cb(a,b,c){function e(){var b=window.innerWidth,e=window.innerHeight;a!==document.body&&
(e=a.getBoundingClientRect(),b=e.right-e.left,e=e.bottom-e.top);g.width=c*b;g.height=c*e;E(g.style,{width:b+"px",height:e+"px"})}var g=document.createElement("canvas");E(g.style,{border:0,margin:0,padding:0,top:0,left:0});a.appendChild(g);a===document.body&&(g.style.position="absolute",E(a.style,{margin:0,padding:0}));window.addEventListener("resize",e,!1);e();return{canvas:g,onDestroy:function(){window.removeEventListener("resize",e);a.removeChild(g)}}}function Db(a,b){function c(c){try{return a.getContext(c,
b)}catch(g){return null}}return c("webgl")||c("experimental-webgl")||c("webgl-experimental")}function $a(a){return"string"===typeof a?a.split():a}function ab(a){return"string"===typeof a?document.querySelector(a):a}function Eb(a){var b=a||{},c,e,g,d;a={};var p=[],f=[],r="undefined"===typeof window?1:window.devicePixelRatio,q=!1,t=function(a){},m=function(){};"string"===typeof b?c=document.querySelector(b):"object"===typeof b&&("string"===typeof b.nodeName&&"function"===typeof b.appendChild&&"function"===
typeof b.getBoundingClientRect?c=b:"function"===typeof b.drawArrays||"function"===typeof b.drawElements?(d=b,g=d.canvas):("gl"in b?d=b.gl:"canvas"in b?g=ab(b.canvas):"container"in b&&(e=ab(b.container)),"attributes"in b&&(a=b.attributes),"extensions"in b&&(p=$a(b.extensions)),"optionalExtensions"in b&&(f=$a(b.optionalExtensions)),"onDone"in b&&(t=b.onDone),"profile"in b&&(q=!!b.profile),"pixelRatio"in b&&(r=+b.pixelRatio)));c&&("canvas"===c.nodeName.toLowerCase()?g=c:e=c);if(!d){if(!g){c=Cb(e||document.body,
t,r);if(!c)return null;g=c.canvas;m=c.onDestroy}d=Db(g,a)}return d?{gl:d,canvas:g,container:e,extensions:p,optionalExtensions:f,pixelRatio:r,profile:q,onDone:t,onDestroy:m}:(m(),t("webgl not supported, try upgrading your browser or graphics drivers http://get.webgl.org"),null)}function Fb(a,b){function c(b){b=b.toLowerCase();var c;try{c=e[b]=a.getExtension(b)}catch(g){}return!!c}for(var e={},g=0;g<b.extensions.length;++g){var d=b.extensions[g];if(!c(d))return b.onDestroy(),b.onDone('"'+d+'" extension is not supported by the current WebGL context, try upgrading your system or a different browser'),
null}b.optionalExtensions.forEach(c);return{extensions:e,restore:function(){Object.keys(e).forEach(function(a){if(e[a]&&!c(a))throw Error("(regl): error restoring extension "+a);})}}}function J(a,b){for(var c=Array(a),e=0;e<a;++e)c[e]=b(e);return c}function bb(a){var b,c;b=(65535<a)<<4;a>>>=b;c=(255<a)<<3;a>>>=c;b|=c;c=(15<a)<<2;a>>>=c;b|=c;c=(3<a)<<1;return b|c|a>>>c>>1}function cb(){function a(a){a:{for(var b=16;268435456>=b;b*=16)if(a<=b){a=b;break a}a=0}b=c[bb(a)>>2];return 0<b.length?b.pop():
new ArrayBuffer(a)}function b(a){c[bb(a.byteLength)>>2].push(a)}var c=J(8,function(){return[]});return{alloc:a,free:b,allocType:function(b,c){var d=null;switch(b){case 5120:d=new Int8Array(a(c),0,c);break;case 5121:d=new Uint8Array(a(c),0,c);break;case 5122:d=new Int16Array(a(2*c),0,c);break;case 5123:d=new Uint16Array(a(2*c),0,c);break;case 5124:d=new Int32Array(a(4*c),0,c);break;case 5125:d=new Uint32Array(a(4*c),0,c);break;case 5126:d=new Float32Array(a(4*c),0,c);break;default:return null}return d.length!==
c?d.subarray(0,c):d},freeType:function(a){b(a.buffer)}}}function ma(a){return!!a&&"object"===typeof a&&Array.isArray(a.shape)&&Array.isArray(a.stride)&&"number"===typeof a.offset&&a.shape.length===a.stride.length&&(Array.isArray(a.data)||M(a.data))}function db(a,b,c,e,g,d){for(var p=0;p<b;++p)for(var f=a[p],r=0;r<c;++r)for(var q=f[r],t=0;t<e;++t)g[d++]=q[t]}function eb(a,b,c,e,g){for(var d=1,p=c+1;p<b.length;++p)d*=b[p];var f=b[c];if(4===b.length-c){var r=b[c+1],q=b[c+2];b=b[c+3];for(p=0;p<f;++p)db(a[p],
r,q,b,e,g),g+=d}else for(p=0;p<f;++p)eb(a[p],b,c+1,e,g),g+=d}function Ha(a){return Ia[Object.prototype.toString.call(a)]|0}function fb(a,b){for(var c=0;c<b.length;++c)a[c]=b[c]}function gb(a,b,c,e,g,d,p){for(var f=0,r=0;r<c;++r)for(var q=0;q<e;++q)a[f++]=b[g*r+d*q+p]}function Gb(a,b,c,e){function g(b){this.id=r++;this.buffer=a.createBuffer();this.type=b;this.usage=35044;this.byteLength=0;this.dimension=1;this.dtype=5121;this.persistentData=null;c.profile&&(this.stats={size:0})}function d(b,c,k){b.byteLength=
c.byteLength;a.bufferData(b.type,c,k)}function p(a,b,c,h,l,e){a.usage=c;if(Array.isArray(b)){if(a.dtype=h||5126,0<b.length)if(Array.isArray(b[0])){l=hb(b);for(var v=h=1;v<l.length;++v)h*=l[v];a.dimension=h;b=Qa(b,l,a.dtype);d(a,b,c);e?a.persistentData=b:x.freeType(b)}else"number"===typeof b[0]?(a.dimension=l,l=x.allocType(a.dtype,b.length),fb(l,b),d(a,l,c),e?a.persistentData=l:x.freeType(l)):M(b[0])&&(a.dimension=b[0].length,a.dtype=h||Ha(b[0])||5126,b=Qa(b,[b.length,b[0].length],a.dtype),d(a,b,c),
e?a.persistentData=b:x.freeType(b))}else if(M(b))a.dtype=h||Ha(b),a.dimension=l,d(a,b,c),e&&(a.persistentData=new Uint8Array(new Uint8Array(b.buffer)));else if(ma(b)){l=b.shape;var g=b.stride,v=b.offset,f=0,q=0,r=0,t=0;1===l.length?(f=l[0],q=1,r=g[0],t=0):2===l.length&&(f=l[0],q=l[1],r=g[0],t=g[1]);a.dtype=h||Ha(b.data)||5126;a.dimension=q;l=x.allocType(a.dtype,f*q);gb(l,b.data,f,q,r,t,v);d(a,l,c);e?a.persistentData=l:x.freeType(l)}else b instanceof ArrayBuffer&&(a.dtype=5121,a.dimension=l,d(a,b,
c),e&&(a.persistentData=new Uint8Array(new Uint8Array(b))))}function f(c){b.bufferCount--;for(var d=0;d<e.state.length;++d){var k=e.state[d];k.buffer===c&&(a.disableVertexAttribArray(d),k.buffer=null)}a.deleteBuffer(c.buffer);c.buffer=null;delete q[c.id]}var r=0,q={};g.prototype.bind=function(){a.bindBuffer(this.type,this.buffer)};g.prototype.destroy=function(){f(this)};var t=[];c.profile&&(b.getTotalBufferSize=function(){var a=0;Object.keys(q).forEach(function(b){a+=q[b].stats.size});return a});
return{create:function(m,e,d,h){function l(b){var m=35044,e=null,d=0,k=0,g=1;Array.isArray(b)||M(b)||ma(b)||b instanceof ArrayBuffer?e=b:"number"===typeof b?d=b|0:b&&("data"in b&&(e=b.data),"usage"in b&&(m=jb[b.usage]),"type"in b&&(k=Ra[b.type]),"dimension"in b&&(g=b.dimension|0),"length"in b&&(d=b.length|0));u.bind();e?p(u,e,m,k,g,h):(d&&a.bufferData(u.type,d,m),u.dtype=k||5121,u.usage=m,u.dimension=g,u.byteLength=d);c.profile&&(u.stats.size=u.byteLength*ja[u.dtype]);return l}b.bufferCount++;var u=
new g(e);q[u.id]=u;d||l(m);l._reglType="buffer";l._buffer=u;l.subdata=function(b,c){var m=(c||0)|0,e;u.bind();if(M(b)||b instanceof ArrayBuffer)a.bufferSubData(u.type,m,b);else if(Array.isArray(b)){if(0<b.length)if("number"===typeof b[0]){var d=x.allocType(u.dtype,b.length);fb(d,b);a.bufferSubData(u.type,m,d);x.freeType(d)}else if(Array.isArray(b[0])||M(b[0]))e=hb(b),d=Qa(b,e,u.dtype),a.bufferSubData(u.type,m,d),x.freeType(d)}else if(ma(b)){e=b.shape;var h=b.stride,k=d=0,g=0,F=0;1===e.length?(d=e[0],
k=1,g=h[0],F=0):2===e.length&&(d=e[0],k=e[1],g=h[0],F=h[1]);e=Array.isArray(b.data)?u.dtype:Ha(b.data);e=x.allocType(e,d*k);gb(e,b.data,d,k,g,F,b.offset);a.bufferSubData(u.type,m,e);x.freeType(e)}return l};c.profile&&(l.stats=u.stats);l.destroy=function(){f(u)};return l},createStream:function(a,b){var c=t.pop();c||(c=new g(a));c.bind();p(c,b,35040,0,1,!1);return c},destroyStream:function(a){t.push(a)},clear:function(){S(q).forEach(f);t.forEach(f)},getBuffer:function(a){return a&&a._buffer instanceof
g?a._buffer:null},restore:function(){S(q).forEach(function(b){b.buffer=a.createBuffer();a.bindBuffer(b.type,b.buffer);a.bufferData(b.type,b.persistentData||b.byteLength,b.usage)})},_initBuffer:p}}function Hb(a,b,c,e){function g(a){this.id=r++;f[this.id]=this;this.buffer=a;this.primType=4;this.type=this.vertCount=0}function d(e,d,g,h,l,u,v){e.buffer.bind();if(d){var f=v;v||M(d)&&(!ma(d)||M(d.data))||(f=b.oes_element_index_uint?5125:5123);c._initBuffer(e.buffer,d,g,f,3)}else a.bufferData(34963,u,g),
e.buffer.dtype=f||5121,e.buffer.usage=g,e.buffer.dimension=3,e.buffer.byteLength=u;f=v;if(!v){switch(e.buffer.dtype){case 5121:case 5120:f=5121;break;case 5123:case 5122:f=5123;break;case 5125:case 5124:f=5125}e.buffer.dtype=f}e.type=f;d=l;0>d&&(d=e.buffer.byteLength,5123===f?d>>=1:5125===f&&(d>>=2));e.vertCount=d;d=h;0>h&&(d=4,h=e.buffer.dimension,1===h&&(d=0),2===h&&(d=1),3===h&&(d=4));e.primType=d}function p(a){e.elementsCount--;delete f[a.id];a.buffer.destroy();a.buffer=null}var f={},r=0,q={uint8:5121,
uint16:5123};b.oes_element_index_uint&&(q.uint32=5125);g.prototype.bind=function(){this.buffer.bind()};var t=[];return{create:function(a,b){function k(a){if(a)if("number"===typeof a)h(a),l.primType=4,l.vertCount=a|0,l.type=5121;else{var b=null,c=35044,e=-1,g=-1,f=0,m=0;if(Array.isArray(a)||M(a)||ma(a))b=a;else if("data"in a&&(b=a.data),"usage"in a&&(c=jb[a.usage]),"primitive"in a&&(e=Sa[a.primitive]),"count"in a&&(g=a.count|0),"type"in a&&(m=q[a.type]),"length"in a)f=a.length|0;else if(f=g,5123===
m||5122===m)f*=2;else if(5125===m||5124===m)f*=4;d(l,b,c,e,g,f,m)}else h(),l.primType=4,l.vertCount=0,l.type=5121;return k}var h=c.create(null,34963,!0),l=new g(h._buffer);e.elementsCount++;k(a);k._reglType="elements";k._elements=l;k.subdata=function(a,b){h.subdata(a,b);return k};k.destroy=function(){p(l)};return k},createStream:function(a){var b=t.pop();b||(b=new g(c.create(null,34963,!0,!1)._buffer));d(b,a,35040,-1,-1,0,0);return b},destroyStream:function(a){t.push(a)},getElements:function(a){return"function"===
typeof a&&a._elements instanceof g?a._elements:null},clear:function(){S(f).forEach(p)}}}function kb(a){for(var b=x.allocType(5123,a.length),c=0;c<a.length;++c)if(isNaN(a[c]))b[c]=65535;else if(Infinity===a[c])b[c]=31744;else if(-Infinity===a[c])b[c]=64512;else{lb[0]=a[c];var e=Ib[0],g=e>>>31<<15,d=(e<<1>>>24)-127,e=e>>13&1023;b[c]=-24>d?g:-14>d?g+(e+1024>>-14-d):15<d?g+31744:g+(d+15<<10)+e}return b}function pa(a){return Array.isArray(a)||M(a)}function Ea(a){return"[object "+a+"]"}function mb(a){return Array.isArray(a)&&
(0===a.length||"number"===typeof a[0])}function nb(a){return Array.isArray(a)&&0!==a.length&&pa(a[0])?!0:!1}function na(a){return Object.prototype.toString.call(a)}function Ta(a){if(!a)return!1;var b=na(a);return 0<=Jb.indexOf(b)?!0:mb(a)||nb(a)||ma(a)}function ob(a,b){36193===a.type?(a.data=kb(b),x.freeType(b)):a.data=b}function Ja(a,b,c,e,g,d){a="undefined"!==typeof z[a]?z[a]:L[a]*qa[b];d&&(a*=6);if(g){for(e=0;1<=c;)e+=a*c*c,c/=2;return e}return a*c*e}function Kb(a,b,c,e,g,d,p){function f(){this.format=
this.internalformat=6408;this.type=5121;this.flipY=this.premultiplyAlpha=this.compressed=!1;this.unpackAlignment=1;this.colorSpace=37444;this.channels=this.height=this.width=0}function r(a,b){a.internalformat=b.internalformat;a.format=b.format;a.type=b.type;a.compressed=b.compressed;a.premultiplyAlpha=b.premultiplyAlpha;a.flipY=b.flipY;a.unpackAlignment=b.unpackAlignment;a.colorSpace=b.colorSpace;a.width=b.width;a.height=b.height;a.channels=b.channels}function q(a,b){if("object"===typeof b&&b){"premultiplyAlpha"in
b&&(a.premultiplyAlpha=b.premultiplyAlpha);"flipY"in b&&(a.flipY=b.flipY);"alignment"in b&&(a.unpackAlignment=b.alignment);"colorSpace"in b&&(a.colorSpace=wa[b.colorSpace]);"type"in b&&(a.type=G[b.type]);var c=a.width,e=a.height,d=a.channels,h=!1;"shape"in b?(c=b.shape[0],e=b.shape[1],3===b.shape.length&&(d=b.shape[2],h=!0)):("radius"in b&&(c=e=b.radius),"width"in b&&(c=b.width),"height"in b&&(e=b.height),"channels"in b&&(d=b.channels,h=!0));a.width=c|0;a.height=e|0;a.channels=d|0;c=!1;"format"in
b&&(c=b.format,e=a.internalformat=U[c],a.format=Lb[e],c in G&&!("type"in b)&&(a.type=G[c]),c in W&&(a.compressed=!0),c=!0);!h&&c?a.channels=L[a.format]:h&&!c&&a.channels!==La[a.format]&&(a.format=a.internalformat=La[a.channels])}}function t(b){a.pixelStorei(37440,b.flipY);a.pixelStorei(37441,b.premultiplyAlpha);a.pixelStorei(37443,b.colorSpace);a.pixelStorei(3317,b.unpackAlignment)}function m(){f.call(this);this.yOffset=this.xOffset=0;this.data=null;this.needsFree=!1;this.element=null;this.needsCopy=
!1}function C(a,b){var c=null;Ta(b)?c=b:b&&(q(a,b),"x"in b&&(a.xOffset=b.x|0),"y"in b&&(a.yOffset=b.y|0),Ta(b.data)&&(c=b.data));if(b.copy){var e=g.viewportWidth,d=g.viewportHeight;a.width=a.width||e-a.xOffset;a.height=a.height||d-a.yOffset;a.needsCopy=!0}else if(!c)a.width=a.width||1,a.height=a.height||1,a.channels=a.channels||4;else if(M(c))a.channels=a.channels||4,a.data=c,"type"in b||5121!==a.type||(a.type=Ia[Object.prototype.toString.call(c)]|0);else if(mb(c)){a.channels=a.channels||4;e=c;d=
e.length;switch(a.type){case 5121:case 5123:case 5125:case 5126:d=x.allocType(a.type,d);d.set(e);a.data=d;break;case 36193:a.data=kb(e)}a.alignment=1;a.needsFree=!0}else if(ma(c)){e=c.data;Array.isArray(e)||5121!==a.type||(a.type=Ia[Object.prototype.toString.call(e)]|0);var d=c.shape,h=c.stride,f,l,n,w;3===d.length?(n=d[2],w=h[2]):w=n=1;f=d[0];l=d[1];d=h[0];h=h[1];a.alignment=1;a.width=f;a.height=l;a.channels=n;a.format=a.internalformat=La[n];a.needsFree=!0;f=w;c=c.offset;n=a.width;w=a.height;l=a.channels;
for(var y=x.allocType(36193===a.type?5126:a.type,n*w*l),I=0,fa=0;fa<w;++fa)for(var ga=0;ga<n;++ga)for(var xa=0;xa<l;++xa)y[I++]=e[d*ga+h*fa+f*xa+c];ob(a,y)}else if(na(c)===Ua||na(c)===pb)na(c)===Ua?a.element=c:a.element=c.canvas,a.width=a.element.width,a.height=a.element.height,a.channels=4;else if(na(c)===qb)a.element=c,a.width=c.width,a.height=c.height,a.channels=4;else if(na(c)===rb)a.element=c,a.width=c.naturalWidth,a.height=c.naturalHeight,a.channels=4;else if(na(c)===sb)a.element=c,a.width=
c.videoWidth,a.height=c.videoHeight,a.channels=4;else if(nb(c)){e=a.width||c[0].length;d=a.height||c.length;h=a.channels;h=pa(c[0][0])?h||c[0][0].length:h||1;f=Ma.shape(c);n=1;for(w=0;w<f.length;++w)n*=f[w];n=x.allocType(36193===a.type?5126:a.type,n);Ma.flatten(c,f,"",n);ob(a,n);a.alignment=1;a.width=e;a.height=d;a.channels=h;a.format=a.internalformat=La[h];a.needsFree=!0}}function k(b,c,d,h,f){var g=b.element,l=b.data,k=b.internalformat,n=b.format,w=b.type,y=b.width,I=b.height;t(b);g?a.texSubImage2D(c,
f,d,h,n,w,g):b.compressed?a.compressedTexSubImage2D(c,f,d,h,k,y,I,l):b.needsCopy?(e(),a.copyTexSubImage2D(c,f,d,h,b.xOffset,b.yOffset,y,I)):a.texSubImage2D(c,f,d,h,y,I,n,w,l)}function h(){return P.pop()||new m}function l(a){a.needsFree&&x.freeType(a.data);m.call(a);P.push(a)}function u(){f.call(this);this.genMipmaps=!1;this.mipmapHint=4352;this.mipmask=0;this.images=Array(16)}function v(a,b,c){var d=a.images[0]=h();a.mipmask=1;d.width=a.width=b;d.height=a.height=c;d.channels=a.channels=4}function N(a,
b){var c=null;if(Ta(b))c=a.images[0]=h(),r(c,a),C(c,b),a.mipmask=1;else if(q(a,b),Array.isArray(b.mipmap))for(var d=b.mipmap,e=0;e<d.length;++e)c=a.images[e]=h(),r(c,a),c.width>>=e,c.height>>=e,C(c,d[e]),a.mipmask|=1<<e;else c=a.images[0]=h(),r(c,a),C(c,b),a.mipmask=1;r(a,a.images[0])}function B(b,c){for(var d=b.images,h=0;h<d.length&&d[h];++h){var f=d[h],g=c,l=h,k=f.element,n=f.data,w=f.internalformat,y=f.format,I=f.type,fa=f.width,ga=f.height,xa=f.channels;t(f);k?a.texImage2D(g,l,y,y,I,k):f.compressed?
a.compressedTexImage2D(g,l,w,fa,ga,0,n):f.needsCopy?(e(),a.copyTexImage2D(g,l,y,f.xOffset,f.yOffset,fa,ga,0)):((f=!n)&&(n=x.zero.allocType(I,fa*ga*xa)),a.texImage2D(g,l,y,fa,ga,0,y,I,n),f&&n&&x.zero.freeType(n))}}function D(){var a=tb.pop()||new u;f.call(a);for(var b=a.mipmask=0;16>b;++b)a.images[b]=null;return a}function ib(a){for(var b=a.images,c=0;c<b.length;++c)b[c]&&l(b[c]),b[c]=null;tb.push(a)}function z(){this.magFilter=this.minFilter=9728;this.wrapT=this.wrapS=33071;this.anisotropic=1;this.genMipmaps=
!1;this.mipmapHint=4352}function O(a,b){"min"in b&&(a.minFilter=Va[b.min],0<=Mb.indexOf(a.minFilter)&&!("faces"in b)&&(a.genMipmaps=!0));"mag"in b&&(a.magFilter=V[b.mag]);var c=a.wrapS,d=a.wrapT;if("wrap"in b){var e=b.wrap;"string"===typeof e?c=d=K[e]:Array.isArray(e)&&(c=K[e[0]],d=K[e[1]])}else"wrapS"in b&&(c=K[b.wrapS]),"wrapT"in b&&(d=K[b.wrapT]);a.wrapS=c;a.wrapT=d;"anisotropic"in b&&(a.anisotropic=b.anisotropic);if("mipmap"in b){c=!1;switch(typeof b.mipmap){case "string":a.mipmapHint=ua[b.mipmap];
c=a.genMipmaps=!0;break;case "boolean":c=a.genMipmaps=b.mipmap;break;case "object":a.genMipmaps=!1,c=!0}!c||"min"in b||(a.minFilter=9984)}}function R(c,d){a.texParameteri(d,10241,c.minFilter);a.texParameteri(d,10240,c.magFilter);a.texParameteri(d,10242,c.wrapS);a.texParameteri(d,10243,c.wrapT);b.ext_texture_filter_anisotropic&&a.texParameteri(d,34046,c.anisotropic);c.genMipmaps&&(a.hint(33170,c.mipmapHint),a.generateMipmap(d))}function F(b){f.call(this);this.mipmask=0;this.internalformat=6408;this.id=
ya++;this.refCount=1;this.target=b;this.texture=a.createTexture();this.unit=-1;this.bindCount=0;this.texInfo=new z;p.profile&&(this.stats={size:0})}function T(b){a.activeTexture(33984);a.bindTexture(b.target,b.texture)}function Aa(){var b=ha[0];b?a.bindTexture(b.target,b.texture):a.bindTexture(3553,null)}function A(b){var c=b.texture,e=b.unit,h=b.target;0<=e&&(a.activeTexture(33984+e),a.bindTexture(h,null),ha[e]=null);a.deleteTexture(c);b.texture=null;b.params=null;b.pixels=null;b.refCount=0;delete X[b.id];
d.textureCount--}var ua={"don't care":4352,"dont care":4352,nice:4354,fast:4353},K={repeat:10497,clamp:33071,mirror:33648},V={nearest:9728,linear:9729},Va=E({mipmap:9987,"nearest mipmap nearest":9984,"linear mipmap nearest":9985,"nearest mipmap linear":9986,"linear mipmap linear":9987},V),wa={none:0,browser:37444},G={uint8:5121,rgba4:32819,rgb565:33635,"rgb5 a1":32820},U={alpha:6406,luminance:6409,"luminance alpha":6410,rgb:6407,rgba:6408,rgba4:32854,"rgb5 a1":32855,rgb565:36194},W={};b.ext_srgb&&
(U.srgb=35904,U.srgba=35906);b.oes_texture_float&&(G.float32=G["float"]=5126);b.oes_texture_half_float&&(G.float16=G["half float"]=36193);b.webgl_depth_texture&&(E(U,{depth:6402,"depth stencil":34041}),E(G,{uint16:5123,uint32:5125,"depth stencil":34042}));b.webgl_compressed_texture_s3tc&&E(W,{"rgb s3tc dxt1":33776,"rgba s3tc dxt1":33777,"rgba s3tc dxt3":33778,"rgba s3tc dxt5":33779});b.webgl_compressed_texture_atc&&E(W,{"rgb atc":35986,"rgba atc explicit alpha":35987,"rgba atc interpolated alpha":34798});
b.webgl_compressed_texture_pvrtc&&E(W,{"rgb pvrtc 4bppv1":35840,"rgb pvrtc 2bppv1":35841,"rgba pvrtc 4bppv1":35842,"rgba pvrtc 2bppv1":35843});b.webgl_compressed_texture_etc1&&(W["rgb etc1"]=36196);var Nb=Array.prototype.slice.call(a.getParameter(34467));Object.keys(W).forEach(function(a){var b=W[a];0<=Nb.indexOf(b)&&(U[a]=b)});var ca=Object.keys(U);c.textureFormats=ca;var J=[];Object.keys(U).forEach(function(a){J[U[a]]=a});var da=[];Object.keys(G).forEach(function(a){da[G[a]]=a});var oa=[];Object.keys(V).forEach(function(a){oa[V[a]]=
a});var za=[];Object.keys(Va).forEach(function(a){za[Va[a]]=a});var ka=[];Object.keys(K).forEach(function(a){ka[K[a]]=a});var Lb=ca.reduce(function(a,b){var c=U[b];6409===c||6406===c||6409===c||6410===c||6402===c||34041===c?a[c]=c:32855===c||0<=b.indexOf("rgba")?a[c]=6408:a[c]=6407;return a},{}),P=[],tb=[],ya=0,X={},ea=c.maxTextureUnits,ha=Array(ea).map(function(){return null});E(F.prototype,{bind:function(){this.bindCount+=1;var b=this.unit;if(0>b){for(var c=0;c<ea;++c){var e=ha[c];if(e){if(0<e.bindCount)continue;
e.unit=-1}ha[c]=this;b=c;break}p.profile&&d.maxTextureUnits<b+1&&(d.maxTextureUnits=b+1);this.unit=b;a.activeTexture(33984+b);a.bindTexture(this.target,this.texture)}return b},unbind:function(){--this.bindCount},decRef:function(){0>=--this.refCount&&A(this)}});p.profile&&(d.getTotalTextureSize=function(){var a=0;Object.keys(X).forEach(function(b){a+=X[b].stats.size});return a});return{create2D:function(b,c){function e(a,b){var c=f.texInfo;z.call(c);var d=D();"number"===typeof a?"number"===typeof b?
v(d,a|0,b|0):v(d,a|0,a|0):a?(O(c,a),N(d,a)):v(d,1,1);c.genMipmaps&&(d.mipmask=(d.width<<1)-1);f.mipmask=d.mipmask;r(f,d);f.internalformat=d.internalformat;e.width=d.width;e.height=d.height;T(f);B(d,3553);R(c,3553);Aa();ib(d);p.profile&&(f.stats.size=Ja(f.internalformat,f.type,d.width,d.height,c.genMipmaps,!1));e.format=J[f.internalformat];e.type=da[f.type];e.mag=oa[c.magFilter];e.min=za[c.minFilter];e.wrapS=ka[c.wrapS];e.wrapT=ka[c.wrapT];return e}var f=new F(3553);X[f.id]=f;d.textureCount++;e(b,
c);e.subimage=function(a,b,c,d){b|=0;c|=0;d|=0;var n=h();r(n,f);n.width=0;n.height=0;C(n,a);n.width=n.width||(f.width>>d)-b;n.height=n.height||(f.height>>d)-c;T(f);k(n,3553,b,c,d);Aa();l(n);return e};e.resize=function(b,c){var d=b|0,h=c|0||d;if(d===f.width&&h===f.height)return e;e.width=f.width=d;e.height=f.height=h;T(f);for(var n,w=f.channels,y=f.type,I=0;f.mipmask>>I;++I){var fa=d>>I,ga=h>>I;if(!fa||!ga)break;n=x.zero.allocType(y,fa*ga*w);a.texImage2D(3553,I,f.format,fa,ga,0,f.format,f.type,n);
n&&x.zero.freeType(n)}Aa();p.profile&&(f.stats.size=Ja(f.internalformat,f.type,d,h,!1,!1));return e};e._reglType="texture2d";e._texture=f;p.profile&&(e.stats=f.stats);e.destroy=function(){f.decRef()};return e},createCube:function(b,c,e,f,g,ua){function A(a,b,c,d,e,f){var H,Y=m.texInfo;z.call(Y);for(H=0;6>H;++H)n[H]=D();if("number"===typeof a||!a)for(a=a|0||1,H=0;6>H;++H)v(n[H],a,a);else if("object"===typeof a)if(b)N(n[0],a),N(n[1],b),N(n[2],c),N(n[3],d),N(n[4],e),N(n[5],f);else if(O(Y,a),q(m,a),"faces"in
a)for(a=a.faces,H=0;6>H;++H)r(n[H],m),N(n[H],a[H]);else for(H=0;6>H;++H)N(n[H],a);r(m,n[0]);m.mipmask=Y.genMipmaps?(n[0].width<<1)-1:n[0].mipmask;m.internalformat=n[0].internalformat;A.width=n[0].width;A.height=n[0].height;T(m);for(H=0;6>H;++H)B(n[H],34069+H);R(Y,34067);Aa();p.profile&&(m.stats.size=Ja(m.internalformat,m.type,A.width,A.height,Y.genMipmaps,!0));A.format=J[m.internalformat];A.type=da[m.type];A.mag=oa[Y.magFilter];A.min=za[Y.minFilter];A.wrapS=ka[Y.wrapS];A.wrapT=ka[Y.wrapT];for(H=0;6>
H;++H)ib(n[H]);return A}var m=new F(34067);X[m.id]=m;d.cubeCount++;var n=Array(6);A(b,c,e,f,g,ua);A.subimage=function(a,b,c,n,d){c|=0;n|=0;d|=0;var e=h();r(e,m);e.width=0;e.height=0;C(e,b);e.width=e.width||(m.width>>d)-c;e.height=e.height||(m.height>>d)-n;T(m);k(e,34069+a,c,n,d);Aa();l(e);return A};A.resize=function(b){b|=0;if(b!==m.width){A.width=m.width=b;A.height=m.height=b;T(m);for(var c=0;6>c;++c)for(var n=0;m.mipmask>>n;++n)a.texImage2D(34069+c,n,m.format,b>>n,b>>n,0,m.format,m.type,null);Aa();
p.profile&&(m.stats.size=Ja(m.internalformat,m.type,A.width,A.height,!1,!0));return A}};A._reglType="textureCube";A._texture=m;p.profile&&(A.stats=m.stats);A.destroy=function(){m.decRef()};return A},clear:function(){for(var b=0;b<ea;++b)a.activeTexture(33984+b),a.bindTexture(3553,null),ha[b]=null;S(X).forEach(A);d.cubeCount=0;d.textureCount=0},getTexture:function(a){return null},restore:function(){for(var b=0;b<ea;++b){var c=ha[b];c&&(c.bindCount=0,c.unit=-1,ha[b]=null)}S(X).forEach(function(b){b.texture=
a.createTexture();a.bindTexture(b.target,b.texture);for(var c=0;32>c;++c)if(0!==(b.mipmask&1<<c))if(3553===b.target)a.texImage2D(3553,c,b.internalformat,b.width>>c,b.height>>c,0,b.internalformat,b.type,null);else for(var d=0;6>d;++d)a.texImage2D(34069+d,c,b.internalformat,b.width>>c,b.height>>c,0,b.internalformat,b.type,null);R(b.texInfo,b.target)})}}}function Ob(a,b,c,e,g,d){function p(a,b,c){this.target=a;this.texture=b;this.renderbuffer=c;var d=a=0;b?(a=b.width,d=b.height):c&&(a=c.width,d=c.height);
this.width=a;this.height=d}function f(a){a&&(a.texture&&a.texture._texture.decRef(),a.renderbuffer&&a.renderbuffer._renderbuffer.decRef())}function r(a,b,c){a&&(a.texture?a.texture._texture.refCount+=1:a.renderbuffer._renderbuffer.refCount+=1)}function q(b,c){c&&(c.texture?a.framebufferTexture2D(36160,b,c.target,c.texture._texture.texture,0):a.framebufferRenderbuffer(36160,b,36161,c.renderbuffer._renderbuffer.renderbuffer))}function t(a){var b=3553,c=null,d=null,e=a;"object"===typeof a&&(e=a.data,
"target"in a&&(b=a.target|0));a=e._reglType;"texture2d"===a?c=e:"textureCube"===a?c=e:"renderbuffer"===a&&(d=e,b=36161);return new p(b,c,d)}function m(a,b,c,d,f){if(c)return a=e.create2D({width:a,height:b,format:d,type:f}),a._texture.refCount=0,new p(3553,a,null);a=g.create({width:a,height:b,format:d});a._renderbuffer.refCount=0;return new p(36161,null,a)}function C(a){return a&&(a.texture||a.renderbuffer)}function k(a,b,c){a&&(a.texture?a.texture.resize(b,c):a.renderbuffer&&a.renderbuffer.resize(b,
c),a.width=b,a.height=c)}function h(){this.id=O++;R[this.id]=this;this.framebuffer=a.createFramebuffer();this.height=this.width=0;this.colorAttachments=[];this.depthStencilAttachment=this.stencilAttachment=this.depthAttachment=null}function l(a){a.colorAttachments.forEach(f);f(a.depthAttachment);f(a.stencilAttachment);f(a.depthStencilAttachment)}function u(b){a.deleteFramebuffer(b.framebuffer);b.framebuffer=null;d.framebufferCount--;delete R[b.id]}function v(b){var d;a.bindFramebuffer(36160,b.framebuffer);
var e=b.colorAttachments;for(d=0;d<e.length;++d)q(36064+d,e[d]);for(d=e.length;d<c.maxColorAttachments;++d)a.framebufferTexture2D(36160,36064+d,3553,null,0);a.framebufferTexture2D(36160,33306,3553,null,0);a.framebufferTexture2D(36160,36096,3553,null,0);a.framebufferTexture2D(36160,36128,3553,null,0);q(36096,b.depthAttachment);q(36128,b.stencilAttachment);q(33306,b.depthStencilAttachment);a.checkFramebufferStatus(36160);a.isContextLost();a.bindFramebuffer(36160,B.next?B.next.framebuffer:null);B.cur=
B.next;a.getError()}function N(a,b){function c(a,b){var d,f=0,h=0,g=!0,k=!0;d=null;var q=!0,u="rgba",p="uint8",N=1,da=null,oa=null,B=null,ka=!1;if("number"===typeof a)f=a|0,h=b|0||f;else if(a){"shape"in a?(h=a.shape,f=h[0],h=h[1]):("radius"in a&&(f=h=a.radius),"width"in a&&(f=a.width),"height"in a&&(h=a.height));if("color"in a||"colors"in a)d=a.color||a.colors,Array.isArray(d);if(!d){"colorCount"in a&&(N=a.colorCount|0);"colorTexture"in a&&(q=!!a.colorTexture,u="rgba4");if("colorType"in a&&(p=a.colorType,
!q))if("half float"===p||"float16"===p)u="rgba16f";else if("float"===p||"float32"===p)u="rgba32f";"colorFormat"in a&&(u=a.colorFormat,0<=x.indexOf(u)?q=!0:0<=D.indexOf(u)&&(q=!1))}if("depthTexture"in a||"depthStencilTexture"in a)ka=!(!a.depthTexture&&!a.depthStencilTexture);"depth"in a&&("boolean"===typeof a.depth?g=a.depth:(da=a.depth,k=!1));"stencil"in a&&("boolean"===typeof a.stencil?k=a.stencil:(oa=a.stencil,g=!1));"depthStencil"in a&&("boolean"===typeof a.depthStencil?g=k=a.depthStencil:(B=a.depthStencil,
k=g=!1))}else f=h=1;var F=null,z=null,E=null,T=null;if(Array.isArray(d))F=d.map(t);else if(d)F=[t(d)];else for(F=Array(N),d=0;d<N;++d)F[d]=m(f,h,q,u,p);f=f||F[0].width;h=h||F[0].height;da?z=t(da):g&&!k&&(z=m(f,h,ka,"depth","uint32"));oa?E=t(oa):k&&!g&&(E=m(f,h,!1,"stencil","uint8"));B?T=t(B):!da&&!oa&&k&&g&&(T=m(f,h,ka,"depth stencil","depth stencil"));g=null;for(d=0;d<F.length;++d)r(F[d],f,h),F[d]&&F[d].texture&&(k=Wa[F[d].texture._texture.format]*Na[F[d].texture._texture.type],null===g&&(g=k));
r(z,f,h);r(E,f,h);r(T,f,h);l(e);e.width=f;e.height=h;e.colorAttachments=F;e.depthAttachment=z;e.stencilAttachment=E;e.depthStencilAttachment=T;c.color=F.map(C);c.depth=C(z);c.stencil=C(E);c.depthStencil=C(T);c.width=e.width;c.height=e.height;v(e);return c}var e=new h;d.framebufferCount++;c(a,b);return E(c,{resize:function(a,b){var d=Math.max(a|0,1),f=Math.max(b|0||d,1);if(d===e.width&&f===e.height)return c;for(var h=e.colorAttachments,g=0;g<h.length;++g)k(h[g],d,f);k(e.depthAttachment,d,f);k(e.stencilAttachment,
d,f);k(e.depthStencilAttachment,d,f);e.width=c.width=d;e.height=c.height=f;v(e);return c},_reglType:"framebuffer",_framebuffer:e,destroy:function(){u(e);l(e)},use:function(a){B.setFBO({framebuffer:c},a)}})}var B={cur:null,next:null,dirty:!1,setFBO:null},x=["rgba"],D=["rgba4","rgb565","rgb5 a1"];b.ext_srgb&&D.push("srgba");b.ext_color_buffer_half_float&&D.push("rgba16f","rgb16f");b.webgl_color_buffer_float&&D.push("rgba32f");var z=["uint8"];b.oes_texture_half_float&&z.push("half float","float16");
b.oes_texture_float&&z.push("float","float32");var O=0,R={};return E(B,{getFramebuffer:function(a){return"function"===typeof a&&"framebuffer"===a._reglType&&(a=a._framebuffer,a instanceof h)?a:null},create:N,createCube:function(a){function b(a){var d,f={color:null},h=0,g=null;d="rgba";var l="uint8",m=1;if("number"===typeof a)h=a|0;else if(a){"shape"in a?h=a.shape[0]:("radius"in a&&(h=a.radius|0),"width"in a?h=a.width|0:"height"in a&&(h=a.height|0));if("color"in a||"colors"in a)g=a.color||a.colors,
Array.isArray(g);g||("colorCount"in a&&(m=a.colorCount|0),"colorType"in a&&(l=a.colorType),"colorFormat"in a&&(d=a.colorFormat));"depth"in a&&(f.depth=a.depth);"stencil"in a&&(f.stencil=a.stencil);"depthStencil"in a&&(f.depthStencil=a.depthStencil)}else h=1;if(g)if(Array.isArray(g))for(a=[],d=0;d<g.length;++d)a[d]=g[d];else a=[g];else for(a=Array(m),g={radius:h,format:d,type:l},d=0;d<m;++d)a[d]=e.createCube(g);f.color=Array(a.length);for(d=0;d<a.length;++d)m=a[d],h=h||m.width,f.color[d]={target:34069,
data:a[d]};for(d=0;6>d;++d){for(m=0;m<a.length;++m)f.color[m].target=34069+d;0<d&&(f.depth=c[0].depth,f.stencil=c[0].stencil,f.depthStencil=c[0].depthStencil);if(c[d])c[d](f);else c[d]=N(f)}return E(b,{width:h,height:h,color:a})}var c=Array(6);b(a);return E(b,{faces:c,resize:function(a){var d=a|0;if(d===b.width)return b;var e=b.color;for(a=0;a<e.length;++a)e[a].resize(d);for(a=0;6>a;++a)c[a].resize(d);b.width=b.height=d;return b},_reglType:"framebufferCube",destroy:function(){c.forEach(function(a){a.destroy()})}})},
clear:function(){S(R).forEach(u)},restore:function(){B.cur=null;B.next=null;B.dirty=!0;S(R).forEach(function(b){b.framebuffer=a.createFramebuffer();v(b)})}})}function ub(){this.w=this.z=this.y=this.x=this.state=0;this.buffer=null;this.size=0;this.normalized=!1;this.type=5126;this.divisor=this.stride=this.offset=0}function Pb(a,b,c,e){a=c.maxAttributes;b=Array(a);for(c=0;c<a;++c)b[c]=new ub;return{Record:ub,scope:{},state:b}}function Qb(a,b,c,e){function g(a,b,c,d){this.name=a;this.id=b;this.location=
c;this.info=d}function d(a,b){for(var c=0;c<a.length;++c)if(a[c].id===b.id){a[c].location=b.location;return}a.push(b)}function p(c,d,e){e=35632===c?q:t;var f=e[d];if(!f){var g=b.str(d),f=a.createShader(c);a.shaderSource(f,g);a.compileShader(f);e[d]=f}return f}function f(a,b){this.id=k++;this.fragId=a;this.vertId=b;this.program=null;this.uniforms=[];this.attributes=[];e.profile&&(this.stats={uniformsCount:0,attributesCount:0})}function r(c,f){var m,k;m=p(35632,c.fragId);k=p(35633,c.vertId);var q=c.program=
a.createProgram();a.attachShader(q,m);a.attachShader(q,k);a.linkProgram(q);var r=a.getProgramParameter(q,35718);e.profile&&(c.stats.uniformsCount=r);var t=c.uniforms;for(m=0;m<r;++m)if(k=a.getActiveUniform(q,m))if(1<k.size)for(var C=0;C<k.size;++C){var z=k.name.replace("[0]","["+C+"]");d(t,new g(z,b.id(z),a.getUniformLocation(q,z),k))}else d(t,new g(k.name,b.id(k.name),a.getUniformLocation(q,k.name),k));r=a.getProgramParameter(q,35721);e.profile&&(c.stats.attributesCount=r);t=c.attributes;for(m=0;m<
r;++m)(k=a.getActiveAttrib(q,m))&&d(t,new g(k.name,b.id(k.name),a.getAttribLocation(q,k.name),k))}var q={},t={},m={},C=[],k=0;e.profile&&(c.getMaxUniformsCount=function(){var a=0;C.forEach(function(b){b.stats.uniformsCount>a&&(a=b.stats.uniformsCount)});return a},c.getMaxAttributesCount=function(){var a=0;C.forEach(function(b){b.stats.attributesCount>a&&(a=b.stats.attributesCount)});return a});return{clear:function(){var b=a.deleteShader.bind(a);S(q).forEach(b);q={};S(t).forEach(b);t={};C.forEach(function(b){a.deleteProgram(b.program)});
C.length=0;m={};c.shaderCount=0},program:function(a,b,d){var e=m[b];e||(e=m[b]={});var g=e[a];g||(g=new f(b,a),c.shaderCount++,r(g,d),e[a]=g,C.push(g));return g},restore:function(){q={};t={};for(var a=0;a<C.length;++a)r(C[a])},shader:p,frag:-1,vert:-1}}function Rb(a,b,c,e,g,d,p){function f(d){var f;f=null===b.next?5121:b.next.colorAttachments[0].texture._texture.type;var g=0,r=0,k=e.framebufferWidth,h=e.framebufferHeight,l=null;M(d)?l=d:d&&(g=d.x|0,r=d.y|0,k=(d.width||e.framebufferWidth-g)|0,h=(d.height||
e.framebufferHeight-r)|0,l=d.data||null);c();d=k*h*4;l||(5121===f?l=new Uint8Array(d):5126===f&&(l=l||new Float32Array(d)));a.pixelStorei(3333,4);a.readPixels(g,r,k,h,6408,f,l);return l}function r(a){var c;b.setFBO({framebuffer:a.framebuffer},function(){c=f(a)});return c}return function(a){return a&&"framebuffer"in a?r(a):f(a)}}function Ba(a){return Array.prototype.slice.call(a)}function Ca(a){return Ba(a).join("")}function Sb(){function a(){var a=[],b=[];return E(function(){a.push.apply(a,Ba(arguments))},
{def:function(){var d="v"+c++;b.push(d);0<arguments.length&&(a.push(d,"="),a.push.apply(a,Ba(arguments)),a.push(";"));return d},toString:function(){return Ca([0<b.length?"var "+b.join(",")+";":"",Ca(a)])}})}function b(){function b(a,e){d(a,e,"=",c.def(a,e),";")}var c=a(),d=a(),e=c.toString,g=d.toString;return E(function(){c.apply(c,Ba(arguments))},{def:c.def,entry:c,exit:d,save:b,set:function(a,d,e){b(a,d);c(a,d,"=",e,";")},toString:function(){return e()+g()}})}var c=0,e=[],g=[],d=a(),p={};return{global:d,
link:function(a){for(var b=0;b<g.length;++b)if(g[b]===a)return e[b];b="g"+c++;e.push(b);g.push(a);return b},block:a,proc:function(a,c){function d(){var a="a"+e.length;e.push(a);return a}var e=[];c=c||0;for(var g=0;g<c;++g)d();var g=b(),C=g.toString;return p[a]=E(g,{arg:d,toString:function(){return Ca(["function(",e.join(),"){",C(),"}"])}})},scope:b,cond:function(){var a=Ca(arguments),c=b(),d=b(),e=c.toString,g=d.toString;return E(c,{then:function(){c.apply(c,Ba(arguments));return this},"else":function(){d.apply(d,
Ba(arguments));return this},toString:function(){var b=g();b&&(b="else{"+b+"}");return Ca(["if(",a,"){",e(),"}",b])}})},compile:function(){var a=['"use strict";',d,"return {"];Object.keys(p).forEach(function(b){a.push('"',b,'":',p[b].toString(),",")});a.push("}");var b=Ca(a).replace(/;/g,";\n").replace(/}/g,"}\n").replace(/{/g,"{\n");return Function.apply(null,e.concat(b)).apply(null,g)}}}function Oa(a){return Array.isArray(a)||M(a)||ma(a)}function vb(a){return a.sort(function(a,c){return"viewport"===
a?-1:"viewport"===c?1:a<c?-1:1})}function Z(a,b,c,e){this.thisDep=a;this.contextDep=b;this.propDep=c;this.append=e}function va(a){return a&&!(a.thisDep||a.contextDep||a.propDep)}function D(a){return new Z(!1,!1,!1,a)}function P(a,b){var c=a.type;return 0===c?(c=a.data.length,new Z(!0,1<=c,2<=c,b)):4===c?(c=a.data,new Z(c.thisDep,c.contextDep,c.propDep,b)):new Z(3===c,2===c,1===c,b)}function Tb(a,b,c,e,g,d,p,f,r,q,t,m,C,k,h){function l(a){return a.replace(".","_")}function u(a,b,c){var d=l(a);Ka.push(a);
Fa[d]=ra[d]=!!c;sa[d]=b}function v(a,b,c){var d=l(a);Ka.push(a);Array.isArray(c)?(ra[d]=c.slice(),Fa[d]=c.slice()):ra[d]=Fa[d]=c;ta[d]=b}function N(){var a=Sb(),c=a.link,d=a.global;a.id=qa++;a.batchId="0";var e=c(na),f=a.shared={props:"a0"};Object.keys(na).forEach(function(a){f[a]=d.def(e,".",a)});var g=a.next={},xa=a.current={};Object.keys(ta).forEach(function(a){Array.isArray(ra[a])&&(g[a]=d.def(f.next,".",a),xa[a]=d.def(f.current,".",a))});var H=a.constants={};Object.keys(aa).forEach(function(a){H[a]=
d.def(JSON.stringify(aa[a]))});a.invoke=function(b,d){switch(d.type){case 0:var e=["this",f.context,f.props,a.batchId];return b.def(c(d.data),".call(",e.slice(0,Math.max(d.data.length+1,4)),")");case 1:return b.def(f.props,d.data);case 2:return b.def(f.context,d.data);case 3:return b.def("this",d.data);case 4:return d.data.append(a,b),d.data.ref}};a.attribCache={};var Y={};a.scopeAttrib=function(a){a=b.id(a);if(a in Y)return Y[a];var d=q.scope[a];d||(d=q.scope[a]=new ya);return Y[a]=c(d)};return a}
function B(a){var b=a["static"];a=a.dynamic;var c;if("profile"in b){var d=!!b.profile;c=D(function(a,b){return d});c.enable=d}else if("profile"in a){var e=a.profile;c=P(e,function(a,b){return a.invoke(b,e)})}return c}function z(a,b){var c=a["static"],d=a.dynamic;if("framebuffer"in c){var e=c.framebuffer;return e?(e=f.getFramebuffer(e),D(function(a,b){var c=a.link(e),d=a.shared;b.set(d.framebuffer,".next",c);d=d.context;b.set(d,".framebufferWidth",c+".width");b.set(d,".framebufferHeight",c+".height");
return c})):D(function(a,b){var c=a.shared;b.set(c.framebuffer,".next","null");c=c.context;b.set(c,".framebufferWidth",c+".drawingBufferWidth");b.set(c,".framebufferHeight",c+".drawingBufferHeight");return"null"})}if("framebuffer"in d){var g=d.framebuffer;return P(g,function(a,b){var c=a.invoke(b,g),d=a.shared,e=d.framebuffer,c=b.def(e,".getFramebuffer(",c,")");b.set(e,".next",c);d=d.context;b.set(d,".framebufferWidth",c+"?"+c+".width:"+d+".drawingBufferWidth");b.set(d,".framebufferHeight",c+"?"+
c+".height:"+d+".drawingBufferHeight");return c})}return null}function x(a,b,c){function d(a){if(a in e){var c=e[a];a=!0;var n=c.x|0,ba=c.y|0,g,h;"width"in c?g=c.width|0:a=!1;"height"in c?h=c.height|0:a=!1;return new Z(!a&&b&&b.thisDep,!a&&b&&b.contextDep,!a&&b&&b.propDep,function(a,b){var d=a.shared.context,e=g;"width"in c||(e=b.def(d,".","framebufferWidth","-",n));var f=h;"height"in c||(f=b.def(d,".","framebufferHeight","-",ba));return[n,ba,e,f]})}if(a in f){var y=f[a];a=P(y,function(a,b){var c=
a.invoke(b,y),d=a.shared.context,e=b.def(c,".x|0"),n=b.def(c,".y|0"),Y=b.def('"width" in ',c,"?",c,".width|0:","(",d,".","framebufferWidth","-",e,")"),c=b.def('"height" in ',c,"?",c,".height|0:","(",d,".","framebufferHeight","-",n,")");return[e,n,Y,c]});b&&(a.thisDep=a.thisDep||b.thisDep,a.contextDep=a.contextDep||b.contextDep,a.propDep=a.propDep||b.propDep);return a}return b?new Z(b.thisDep,b.contextDep,b.propDep,function(a,b){var c=a.shared.context;return[0,0,b.def(c,".","framebufferWidth"),b.def(c,
".","framebufferHeight")]}):null}var e=a["static"],f=a.dynamic;if(a=d("viewport")){var g=a;a=new Z(a.thisDep,a.contextDep,a.propDep,function(a,b){var c=g.append(a,b),d=a.shared.context;b.set(d,".viewportWidth",c[2]);b.set(d,".viewportHeight",c[3]);return c})}return{viewport:a,scissor_box:d("scissor.box")}}function E(a){function c(a){if(a in d){var n=b.id(d[a]);a=D(function(){return n});a.id=n;return a}if(a in e){var f=e[a];return P(f,function(a,b){var c=a.invoke(b,f);return b.def(a.shared.strings,
".id(",c,")")})}return null}var d=a["static"],e=a.dynamic,f=c("frag"),g=c("vert"),h=null;va(f)&&va(g)?(h=t.program(g.id,f.id),a=D(function(a,b){return a.link(h)})):a=new Z(f&&f.thisDep||g&&g.thisDep,f&&f.contextDep||g&&g.contextDep,f&&f.propDep||g&&g.propDep,function(a,b){var c=a.shared.shader,d;d=f?f.append(a,b):b.def(c,".","frag");var e;e=g?g.append(a,b):b.def(c,".","vert");return b.def(c+".program("+e+","+d+")")});return{frag:f,vert:g,progVar:a,program:h}}function O(a,b){function c(a,b){if(a in
e){var d=e[a]|0;return D(function(a,c){b&&(a.OFFSET=d);return d})}if(a in f){var n=f[a];return P(n,function(a,c){var d=a.invoke(c,n);b&&(a.OFFSET=d);return d})}return b&&g?D(function(a,b){a.OFFSET="0";return 0}):null}var e=a["static"],f=a.dynamic,g=function(){if("elements"in e){var a=e.elements;Oa(a)?a=d.getElements(d.create(a,!0)):a&&(a=d.getElements(a));var b=D(function(b,c){if(a){var d=b.link(a);return b.ELEMENTS=d}return b.ELEMENTS=null});b.value=a;return b}if("elements"in f){var c=f.elements;
return P(c,function(a,b){var d=a.shared,e=d.isBufferArgs,d=d.elements,n=a.invoke(b,c),f=b.def("null"),e=b.def(e,"(",n,")"),n=a.cond(e).then(f,"=",d,".createStream(",n,");")["else"](f,"=",d,".getElements(",n,");");b.entry(n);b.exit(a.cond(e).then(d,".destroyStream(",f,");"));return a.ELEMENTS=f})}return null}(),h=c("offset",!0);return{elements:g,primitive:function(){if("primitive"in e){var a=e.primitive;return D(function(b,c){return Sa[a]})}if("primitive"in f){var b=f.primitive;return P(b,function(a,
c){var d=a.constants.primTypes,e=a.invoke(c,b);return c.def(d,"[",e,"]")})}return g?va(g)?g.value?D(function(a,b){return b.def(a.ELEMENTS,".primType")}):D(function(){return 4}):new Z(g.thisDep,g.contextDep,g.propDep,function(a,b){var c=a.ELEMENTS;return b.def(c,"?",c,".primType:",4)}):null}(),count:function(){if("count"in e){var a=e.count|0;return D(function(){return a})}if("count"in f){var b=f.count;return P(b,function(a,c){return a.invoke(c,b)})}return g?va(g)?g?h?new Z(h.thisDep,h.contextDep,h.propDep,
function(a,b){return b.def(a.ELEMENTS,".vertCount-",a.OFFSET)}):D(function(a,b){return b.def(a.ELEMENTS,".vertCount")}):D(function(){return-1}):new Z(g.thisDep||h.thisDep,g.contextDep||h.contextDep,g.propDep||h.propDep,function(a,b){var c=a.ELEMENTS;return a.OFFSET?b.def(c,"?",c,".vertCount-",a.OFFSET,":-1"):b.def(c,"?",c,".vertCount:-1")}):null}(),instances:c("instances",!1),offset:h}}function R(a,b){var c=a["static"],d=a.dynamic,e={};Ka.forEach(function(a){function b(f,g){if(a in c){var w=f(c[a]);
e[n]=D(function(){return w})}else if(a in d){var h=d[a];e[n]=P(h,function(a,b){return g(a,b,a.invoke(b,h))})}}var n=l(a);switch(a){case "cull.enable":case "blend.enable":case "dither":case "stencil.enable":case "depth.enable":case "scissor.enable":case "polygonOffset.enable":case "sample.alpha":case "sample.enable":case "depth.mask":return b(function(a){return a},function(a,b,c){return c});case "depth.func":return b(function(a){return Xa[a]},function(a,b,c){return b.def(a.constants.compareFuncs,"[",
c,"]")});case "depth.range":return b(function(a){return a},function(a,b,c){a=b.def("+",c,"[0]");b=b.def("+",c,"[1]");return[a,b]});case "blend.func":return b(function(a){return[Ga["srcRGB"in a?a.srcRGB:a.src],Ga["dstRGB"in a?a.dstRGB:a.dst],Ga["srcAlpha"in a?a.srcAlpha:a.src],Ga["dstAlpha"in a?a.dstAlpha:a.dst]]},function(a,b,c){function d(a,e){return b.def('"',a,e,'" in ',c,"?",c,".",a,e,":",c,".",a)}a=a.constants.blendFuncs;var e=d("src","RGB"),n=d("dst","RGB"),e=b.def(a,"[",e,"]"),f=b.def(a,"[",
d("src","Alpha"),"]"),n=b.def(a,"[",n,"]");a=b.def(a,"[",d("dst","Alpha"),"]");return[e,n,f,a]});case "blend.equation":return b(function(a){if("string"===typeof a)return[X[a],X[a]];if("object"===typeof a)return[X[a.rgb],X[a.alpha]]},function(a,b,c){var d=a.constants.blendEquations,e=b.def(),n=b.def();a=a.cond("typeof ",c,'==="string"');a.then(e,"=",n,"=",d,"[",c,"];");a["else"](e,"=",d,"[",c,".rgb];",n,"=",d,"[",c,".alpha];");b(a);return[e,n]});case "blend.color":return b(function(a){return J(4,function(b){return+a[b]})},
function(a,b,c){return J(4,function(a){return b.def("+",c,"[",a,"]")})});case "stencil.mask":return b(function(a){return a|0},function(a,b,c){return b.def(c,"|0")});case "stencil.func":return b(function(a){return[Xa[a.cmp||"keep"],a.ref||0,"mask"in a?a.mask:-1]},function(a,b,c){a=b.def('"cmp" in ',c,"?",a.constants.compareFuncs,"[",c,".cmp]",":",7680);var d=b.def(c,".ref|0");b=b.def('"mask" in ',c,"?",c,".mask|0:-1");return[a,d,b]});case "stencil.opFront":case "stencil.opBack":return b(function(b){return["stencil.opBack"===
a?1029:1028,Pa[b.fail||"keep"],Pa[b.zfail||"keep"],Pa[b.zpass||"keep"]]},function(b,c,d){function e(a){return c.def('"',a,'" in ',d,"?",n,"[",d,".",a,"]:",7680)}var n=b.constants.stencilOps;return["stencil.opBack"===a?1029:1028,e("fail"),e("zfail"),e("zpass")]});case "polygonOffset.offset":return b(function(a){return[a.factor|0,a.units|0]},function(a,b,c){a=b.def(c,".factor|0");b=b.def(c,".units|0");return[a,b]});case "cull.face":return b(function(a){var b=0;"front"===a?b=1028:"back"===a&&(b=1029);
return b},function(a,b,c){return b.def(c,'==="front"?',1028,":",1029)});case "lineWidth":return b(function(a){return a},function(a,b,c){return c});case "frontFace":return b(function(a){return wb[a]},function(a,b,c){return b.def(c+'==="cw"?2304:2305')});case "colorMask":return b(function(a){return a.map(function(a){return!!a})},function(a,b,c){return J(4,function(a){return"!!"+c+"["+a+"]"})});case "sample.coverage":return b(function(a){return["value"in a?a.value:1,!!a.invert]},function(a,b,c){a=b.def('"value" in ',
c,"?+",c,".value:1");b=b.def("!!",c,".invert");return[a,b]})}});return e}function F(a,b){var c=a["static"],d=a.dynamic,e={};Object.keys(c).forEach(function(a){var b=c[a],d;if("number"===typeof b||"boolean"===typeof b)d=D(function(){return b});else if("function"===typeof b){var n=b._reglType;if("texture2d"===n||"textureCube"===n)d=D(function(a){return a.link(b)});else if("framebuffer"===n||"framebufferCube"===n)d=D(function(a){return a.link(b.color[0])})}else pa(b)&&(d=D(function(a){return a.global.def("[",
J(b.length,function(a){return b[a]}),"]")}));d.value=b;e[a]=d});Object.keys(d).forEach(function(a){var b=d[a];e[a]=P(b,function(a,c){return a.invoke(c,b)})});return e}function T(a,c){var d=a["static"],e=a.dynamic,f={};Object.keys(d).forEach(function(a){var c=d[a],e=b.id(a),n=new ya;if(Oa(c))n.state=1,n.buffer=g.getBuffer(g.create(c,34962,!1,!0)),n.type=0;else{var w=g.getBuffer(c);if(w)n.state=1,n.buffer=w,n.type=0;else if("constant"in c){var h=c.constant;n.buffer="null";n.state=2;"number"===typeof h?
n.x=h:Da.forEach(function(a,b){b<h.length&&(n[a]=h[b])})}else{var w=Oa(c.buffer)?g.getBuffer(g.create(c.buffer,34962,!1,!0)):g.getBuffer(c.buffer),k=c.offset|0,m=c.stride|0,I=c.size|0,l=!!c.normalized,p=0;"type"in c&&(p=Ra[c.type]);c=c.divisor|0;n.buffer=w;n.state=1;n.size=I;n.normalized=l;n.type=p||w.dtype;n.offset=k;n.stride=m;n.divisor=c}}f[a]=D(function(a,b){var c=a.attribCache;if(e in c)return c[e];var d={isStream:!1};Object.keys(n).forEach(function(a){d[a]=n[a]});n.buffer&&(d.buffer=a.link(n.buffer),
d.type=d.type||d.buffer+".dtype");return c[e]=d})});Object.keys(e).forEach(function(a){var b=e[a];f[a]=P(b,function(a,c){function d(a){c(w[a],"=",e,".",a,"|0;")}var e=a.invoke(c,b),n=a.shared,f=a.constants,g=n.isBufferArgs,n=n.buffer,w={isStream:c.def(!1)},h=new ya;h.state=1;Object.keys(h).forEach(function(a){w[a]=c.def(""+h[a])});var y=w.buffer,k=w.type;c("if(",g,"(",e,")){",w.isStream,"=true;",y,"=",n,".createStream(",34962,",",e,");",k,"=",y,".dtype;","}else{",y,"=",n,".getBuffer(",e,");","if(",
y,"){",k,"=",y,".dtype;",'}else if("constant" in ',e,"){",w.state,"=",2,";","if(typeof "+e+'.constant === "number"){',w[Da[0]],"=",e,".constant;",Da.slice(1).map(function(a){return w[a]}).join("="),"=0;","}else{",Da.map(function(a,b){return w[a]+"="+e+".constant.length>"+b+"?"+e+".constant["+b+"]:0;"}).join(""),"}}else{","if(",g,"(",e,".buffer)){",y,"=",n,".createStream(",34962,",",e,".buffer);","}else{",y,"=",n,".getBuffer(",e,".buffer);","}",k,'="type" in ',e,"?",f.glTypes,"[",e,".type]:",y,".dtype;",
w.normalized,"=!!",e,".normalized;");d("size");d("offset");d("stride");d("divisor");c("}}");c.exit("if(",w.isStream,"){",n,".destroyStream(",y,");","}");return w})});return f}function M(a){var b=a["static"],c=a.dynamic,d={};Object.keys(b).forEach(function(a){var c=b[a];d[a]=D(function(a,b){return"number"===typeof c||"boolean"===typeof c?""+c:a.link(c)})});Object.keys(c).forEach(function(a){var b=c[a];d[a]=P(b,function(a,c){return a.invoke(c,b)})});return d}function A(a,b,c,d,e){var f=z(a,e),g=x(a,
f,e),h=O(a,e),k=R(a,e),m=E(a,e),ba=g.viewport;ba&&(k.viewport=ba);ba=l("scissor.box");(g=g[ba])&&(k[ba]=g);g=0<Object.keys(k).length;f={framebuffer:f,draw:h,shader:m,state:k,dirty:g};f.profile=B(a,e);f.uniforms=F(c,e);f.attributes=T(b,e);f.context=M(d,e);return f}function ua(a,b,c){var d=a.shared.context,e=a.scope();Object.keys(c).forEach(function(f){b.save(d,"."+f);e(d,".",f,"=",c[f].append(a,b),";")});b(e)}function K(a,b,c,d){var e=a.shared,f=e.gl,g=e.framebuffer,h;ha&&(h=b.def(e.extensions,".webgl_draw_buffers"));
var k=a.constants,e=k.drawBuffer,k=k.backBuffer;a=c?c.append(a,b):b.def(g,".next");d||b("if(",a,"!==",g,".cur){");b("if(",a,"){",f,".bindFramebuffer(",36160,",",a,".framebuffer);");ha&&b(h,".drawBuffersWEBGL(",e,"[",a,".colorAttachments.length]);");b("}else{",f,".bindFramebuffer(",36160,",null);");ha&&b(h,".drawBuffersWEBGL(",k,");");b("}",g,".cur=",a,";");d||b("}")}function V(a,b,c){var d=a.shared,e=d.gl,f=a.current,g=a.next,h=d.current,k=d.next,m=a.cond(h,".dirty");Ka.forEach(function(b){b=l(b);
if(!(b in c.state)){var d,w;if(b in g){d=g[b];w=f[b];var I=J(ra[b].length,function(a){return m.def(d,"[",a,"]")});m(a.cond(I.map(function(a,b){return a+"!=="+w+"["+b+"]"}).join("||")).then(e,".",ta[b],"(",I,");",I.map(function(a,b){return w+"["+b+"]="+a}).join(";"),";"))}else d=m.def(k,".",b),I=a.cond(d,"!==",h,".",b),m(I),b in sa?I(a.cond(d).then(e,".enable(",sa[b],");")["else"](e,".disable(",sa[b],");"),h,".",b,"=",d,";"):I(e,".",ta[b],"(",d,");",h,".",b,"=",d,";")}});0===Object.keys(c.state).length&&
m(h,".dirty=false;");b(m)}function Q(a,b,c,d){var e=a.shared,f=a.current,g=e.current,h=e.gl;vb(Object.keys(c)).forEach(function(e){var k=c[e];if(!d||d(k)){var m=k.append(a,b);if(sa[e]){var l=sa[e];va(k)?m?b(h,".enable(",l,");"):b(h,".disable(",l,");"):b(a.cond(m).then(h,".enable(",l,");")["else"](h,".disable(",l,");"));b(g,".",e,"=",m,";")}else if(pa(m)){var p=f[e];b(h,".",ta[e],"(",m,");",m.map(function(a,b){return p+"["+b+"]="+a}).join(";"),";")}else b(h,".",ta[e],"(",m,");",g,".",e,"=",m,";")}})}
function wa(a,b){ea&&(a.instancing=b.def(a.shared.extensions,".angle_instanced_arrays"))}function G(a,b,c,d,e){function f(){return"undefined"===typeof performance?"Date.now()":"performance.now()"}function g(a){t=b.def();a(t,"=",f(),";");"string"===typeof e?a(ba,".count+=",e,";"):a(ba,".count++;");k&&(d?(r=b.def(),a(r,"=",q,".getNumPendingQueries();")):a(q,".beginQuery(",ba,");"))}function h(a){a(ba,".cpuTime+=",f(),"-",t,";");k&&(d?a(q,".pushScopeStats(",r,",",q,".getNumPendingQueries(),",ba,");"):
a(q,".endQuery();"))}function m(a){var c=b.def(p,".profile");b(p,".profile=",a,";");b.exit(p,".profile=",c,";")}var l=a.shared,ba=a.stats,p=l.current,q=l.timer;c=c.profile;var t,r;if(c){if(va(c)){c.enable?(g(b),h(b.exit),m("true")):m("false");return}c=c.append(a,b);m(c)}else c=b.def(p,".profile");l=a.block();g(l);b("if(",c,"){",l,"}");a=a.block();h(a);b.exit("if(",c,"){",a,"}")}function U(a,b,c,d,e){function f(a){switch(a){case 35664:case 35667:case 35671:return 2;case 35665:case 35668:case 35672:return 3;
case 35666:case 35669:case 35673:return 4;default:return 1}}function g(c,d,e){function f(){b("if(!",y,".buffer){",k,".enableVertexAttribArray(",l,");}");var c=e.type,g;g=e.size?b.def(e.size,"||",d):d;b("if(",y,".type!==",c,"||",y,".size!==",g,"||",q.map(function(a){return y+"."+a+"!=="+e[a]}).join("||"),"){",k,".bindBuffer(",34962,",",I,".buffer);",k,".vertexAttribPointer(",[l,g,c,e.normalized,e.stride,e.offset],");",y,".type=",c,";",y,".size=",g,";",q.map(function(a){return y+"."+a+"="+e[a]+";"}).join(""),
"}");ea&&(c=e.divisor,b("if(",y,".divisor!==",c,"){",a.instancing,".vertexAttribDivisorANGLE(",[l,c],");",y,".divisor=",c,";}"))}function m(){b("if(",y,".buffer){",k,".disableVertexAttribArray(",l,");",y,".buffer=null;","}if(",Da.map(function(a,b){return y+"."+a+"!=="+p[b]}).join("||"),"){",k,".vertexAttrib4f(",l,",",p,");",Da.map(function(a,b){return y+"."+a+"="+p[b]+";"}).join(""),"}")}var k=h.gl,l=b.def(c,".location"),y=b.def(h.attributes,"[",l,"]");c=e.state;var I=e.buffer,p=[e.x,e.y,e.z,e.w],
q=["buffer","normalized","offset","stride"];1===c?f():2===c?m():(b("if(",c,"===",1,"){"),f(),b("}else{"),m(),b("}"))}var h=a.shared;d.forEach(function(d){var h=d.name,k=c.attributes[h],m;if(k){if(!e(k))return;m=k.append(a,b)}else{if(!e(xb))return;var l=a.scopeAttrib(h);m={};Object.keys(new ya).forEach(function(a){m[a]=b.def(l,".",a)})}g(a.link(d),f(d.info.type),m)})}function W(a,c,d,e,f){for(var g=a.shared,h=g.gl,k,m=0;m<e.length;++m){var l=e[m],p=l.name,q=l.info.type,t=d.uniforms[p],l=a.link(l)+
".location",r;if(t){if(!f(t))continue;if(va(t)){p=t.value;if(35678===q||35680===q)q=a.link(p._texture||p.color[0]._texture),c(h,".uniform1i(",l,",",q+".bind());"),c.exit(q,".unbind();");else if(35674===q||35675===q||35676===q)p=a.global.def("new Float32Array(["+Array.prototype.slice.call(p)+"])"),t=2,35675===q?t=3:35676===q&&(t=4),c(h,".uniformMatrix",t,"fv(",l,",false,",p,");");else{switch(q){case 5126:k="1f";break;case 35664:k="2f";break;case 35665:k="3f";break;case 35666:k="4f";break;case 35670:k=
"1i";break;case 5124:k="1i";break;case 35671:k="2i";break;case 35667:k="2i";break;case 35672:k="3i";break;case 35668:k="3i";break;case 35673:k="4i";break;case 35669:k="4i"}c(h,".uniform",k,"(",l,",",pa(p)?Array.prototype.slice.call(p):p,");")}continue}else r=t.append(a,c)}else{if(!f(xb))continue;r=c.def(g.uniforms,"[",b.id(p),"]")}35678===q?c("if(",r,"&&",r,'._reglType==="framebuffer"){',r,"=",r,".color[0];","}"):35680===q&&c("if(",r,"&&",r,'._reglType==="framebufferCube"){',r,"=",r,".color[0];",
"}");p=1;switch(q){case 35678:case 35680:q=c.def(r,"._texture");c(h,".uniform1i(",l,",",q,".bind());");c.exit(q,".unbind();");continue;case 5124:case 35670:k="1i";break;case 35667:case 35671:k="2i";p=2;break;case 35668:case 35672:k="3i";p=3;break;case 35669:case 35673:k="4i";p=4;break;case 5126:k="1f";break;case 35664:k="2f";p=2;break;case 35665:k="3f";p=3;break;case 35666:k="4f";p=4;break;case 35674:k="Matrix2fv";break;case 35675:k="Matrix3fv";break;case 35676:k="Matrix4fv"}c(h,".uniform",k,"(",
l,",");if("M"===k.charAt(0)){var l=Math.pow(q-35674+2,2),v=a.global.def("new Float32Array(",l,")");c("false,(Array.isArray(",r,")||",r," instanceof Float32Array)?",r,":(",J(l,function(a){return v+"["+a+"]="+r+"["+a+"]"}),",",v,")")}else 1<p?c(J(p,function(a){return r+"["+a+"]"})):c(r);c(");")}}function S(a,b,c,d){function e(f){var g=l[f];return g?g.contextDep&&d.contextDynamic||g.propDep?g.append(a,c):g.append(a,b):b.def(m,".",f)}function f(){function a(){c(u,".drawElementsInstancedANGLE(",[q,t,C,
r+"<<(("+C+"-5121)>>1)",v],");")}function b(){c(u,".drawArraysInstancedANGLE(",[q,r,t,v],");")}p?da?a():(c("if(",p,"){"),a(),c("}else{"),b(),c("}")):b()}function g(){function a(){c(k+".drawElements("+[q,t,C,r+"<<(("+C+"-5121)>>1)"]+");")}function b(){c(k+".drawArrays("+[q,r,t]+");")}p?da?a():(c("if(",p,"){"),a(),c("}else{"),b(),c("}")):b()}var h=a.shared,k=h.gl,m=h.draw,l=d.draw,p=function(){var e=l.elements,f=b;if(e){if(e.contextDep&&d.contextDynamic||e.propDep)f=c;e=e.append(a,f)}else e=f.def(m,
".","elements");e&&f("if("+e+")"+k+".bindBuffer(34963,"+e+".buffer.buffer);");return e}(),q=e("primitive"),r=e("offset"),t=function(){var e=l.count,f=b;if(e){if(e.contextDep&&d.contextDynamic||e.propDep)f=c;e=e.append(a,f)}else e=f.def(m,".","count");return e}();if("number"===typeof t){if(0===t)return}else c("if(",t,"){"),c.exit("}");var v,u;ea&&(v=e("instances"),u=a.instancing);var C=p+".type",da=l.elements&&va(l.elements);ea&&("number"!==typeof v||0<=v)?"string"===typeof v?(c("if(",v,">0){"),f(),
c("}else if(",v,"<0){"),g(),c("}")):f():g()}function ca(a,b,c,d,e){b=N();e=b.proc("body",e);ea&&(b.instancing=e.def(b.shared.extensions,".angle_instanced_arrays"));a(b,e,c,d);return b.compile().body}function L(a,b,c,d){wa(a,b);U(a,b,c,d.attributes,function(){return!0});W(a,b,c,d.uniforms,function(){return!0});S(a,b,b,c)}function da(a,b){var c=a.proc("draw",1);wa(a,c);ua(a,c,b.context);K(a,c,b.framebuffer);V(a,c,b);Q(a,c,b.state);G(a,c,b,!1,!0);var d=b.shader.progVar.append(a,c);c(a.shared.gl,".useProgram(",
d,".program);");if(b.shader.program)L(a,c,b,b.shader.program);else{var e=a.global.def("{}"),f=c.def(d,".id"),g=c.def(e,"[",f,"]");c(a.cond(g).then(g,".call(this,a0);")["else"](g,"=",e,"[",f,"]=",a.link(function(c){return ca(L,a,b,c,1)}),"(",d,");",g,".call(this,a0);"))}0<Object.keys(b.state).length&&c(a.shared.current,".dirty=true;")}function oa(a,b,c,d){function e(){return!0}a.batchId="a1";wa(a,b);U(a,b,c,d.attributes,e);W(a,b,c,d.uniforms,e);S(a,b,b,c)}function za(a,b,c,d){function e(a){return a.contextDep&&
g||a.propDep}function f(a){return!e(a)}wa(a,b);var g=c.contextDep,h=b.def(),k=b.def();a.shared.props=k;a.batchId=h;var m=a.scope(),l=a.scope();b(m.entry,"for(",h,"=0;",h,"<","a1",";++",h,"){",k,"=","a0","[",h,"];",l,"}",m.exit);c.needsContext&&ua(a,l,c.context);c.needsFramebuffer&&K(a,l,c.framebuffer);Q(a,l,c.state,e);c.profile&&e(c.profile)&&G(a,l,c,!1,!0);d?(U(a,m,c,d.attributes,f),U(a,l,c,d.attributes,e),W(a,m,c,d.uniforms,f),W(a,l,c,d.uniforms,e),S(a,m,l,c)):(b=a.global.def("{}"),d=c.shader.progVar.append(a,
l),k=l.def(d,".id"),m=l.def(b,"[",k,"]"),l(a.shared.gl,".useProgram(",d,".program);","if(!",m,"){",m,"=",b,"[",k,"]=",a.link(function(b){return ca(oa,a,c,b,2)}),"(",d,");}",m,".call(this,a0[",h,"],",h,");"))}function ka(a,b){function c(a){return a.contextDep&&e||a.propDep}var d=a.proc("batch",2);a.batchId="0";wa(a,d);var e=!1,f=!0;Object.keys(b.context).forEach(function(a){e=e||b.context[a].propDep});e||(ua(a,d,b.context),f=!1);var g=b.framebuffer,h=!1;g?(g.propDep?e=h=!0:g.contextDep&&e&&(h=!0),
h||K(a,d,g)):K(a,d,null);b.state.viewport&&b.state.viewport.propDep&&(e=!0);V(a,d,b);Q(a,d,b.state,function(a){return!c(a)});b.profile&&c(b.profile)||G(a,d,b,!1,"a1");b.contextDep=e;b.needsContext=f;b.needsFramebuffer=h;f=b.shader.progVar;if(f.contextDep&&e||f.propDep)za(a,d,b,null);else if(f=f.append(a,d),d(a.shared.gl,".useProgram(",f,".program);"),b.shader.program)za(a,d,b,b.shader.program);else{var g=a.global.def("{}"),h=d.def(f,".id"),k=d.def(g,"[",h,"]");d(a.cond(k).then(k,".call(this,a0,a1);")["else"](k,
"=",g,"[",h,"]=",a.link(function(c){return ca(za,a,b,c,2)}),"(",f,");",k,".call(this,a0,a1);"))}0<Object.keys(b.state).length&&d(a.shared.current,".dirty=true;")}function ia(a,c){function d(b){var g=c.shader[b];g&&e.set(f.shader,"."+b,g.append(a,e))}var e=a.proc("scope",3);a.batchId="a2";var f=a.shared,g=f.current;ua(a,e,c.context);c.framebuffer&&c.framebuffer.append(a,e);vb(Object.keys(c.state)).forEach(function(b){var d=c.state[b].append(a,e);pa(d)?d.forEach(function(c,d){e.set(a.next[b],"["+d+
"]",c)}):e.set(f.next,"."+b,d)});G(a,e,c,!0,!0);["elements","offset","count","instances","primitive"].forEach(function(b){var d=c.draw[b];d&&e.set(f.draw,"."+b,""+d.append(a,e))});Object.keys(c.uniforms).forEach(function(d){e.set(f.uniforms,"["+b.id(d)+"]",c.uniforms[d].append(a,e))});Object.keys(c.attributes).forEach(function(b){var d=c.attributes[b].append(a,e),f=a.scopeAttrib(b);Object.keys(new ya).forEach(function(a){e.set(f,"."+a,d[a])})});d("vert");d("frag");0<Object.keys(c.state).length&&(e(g,
".dirty=true;"),e.exit(g,".dirty=true;"));e("a1(",a.shared.context,",a0,",a.batchId,");")}function ma(a){if("object"===typeof a&&!pa(a)){for(var b=Object.keys(a),c=0;c<b.length;++c)if(la.isDynamic(a[b[c]]))return!0;return!1}}function ja(a,b,c){function d(a,b){g.forEach(function(c){var d=e[c];la.isDynamic(d)&&(d=a.invoke(b,d),b(l,".",c,"=",d,";"))})}var e=b["static"][c];if(e&&ma(e)){var f=a.global,g=Object.keys(e),h=!1,k=!1,m=!1,l=a.global.def("{}");g.forEach(function(b){var c=e[b];if(la.isDynamic(c))"function"===
typeof c&&(c=e[b]=la.unbox(c)),b=P(c,null),h=h||b.thisDep,m=m||b.propDep,k=k||b.contextDep;else{f(l,".",b,"=");switch(typeof c){case "number":f(c);break;case "string":f('"',c,'"');break;case "object":Array.isArray(c)&&f("[",c.join(),"]");break;default:f(a.link(c))}f(";")}});b.dynamic[c]=new la.DynamicVariable(4,{thisDep:h,contextDep:k,propDep:m,ref:l,append:d});delete b["static"][c]}}var ya=q.Record,X={add:32774,subtract:32778,"reverse subtract":32779};c.ext_blend_minmax&&(X.min=32775,X.max=32776);
var ea=c.angle_instanced_arrays,ha=c.webgl_draw_buffers,ra={dirty:!0,profile:h.profile},Fa={},Ka=[],sa={},ta={};u("dither",3024);u("blend.enable",3042);v("blend.color","blendColor",[0,0,0,0]);v("blend.equation","blendEquationSeparate",[32774,32774]);v("blend.func","blendFuncSeparate",[1,0,1,0]);u("depth.enable",2929,!0);v("depth.func","depthFunc",513);v("depth.range","depthRange",[0,1]);v("depth.mask","depthMask",!0);v("colorMask","colorMask",[!0,!0,!0,!0]);u("cull.enable",2884);v("cull.face","cullFace",
1029);v("frontFace","frontFace",2305);v("lineWidth","lineWidth",1);u("polygonOffset.enable",32823);v("polygonOffset.offset","polygonOffset",[0,0]);u("sample.alpha",32926);u("sample.enable",32928);v("sample.coverage","sampleCoverage",[1,!1]);u("stencil.enable",2960);v("stencil.mask","stencilMask",-1);v("stencil.func","stencilFunc",[519,0,-1]);v("stencil.opFront","stencilOpSeparate",[1028,7680,7680,7680]);v("stencil.opBack","stencilOpSeparate",[1029,7680,7680,7680]);u("scissor.enable",3089);v("scissor.box",
"scissor",[0,0,a.drawingBufferWidth,a.drawingBufferHeight]);v("viewport","viewport",[0,0,a.drawingBufferWidth,a.drawingBufferHeight]);var na={gl:a,context:C,strings:b,next:Fa,current:ra,draw:m,elements:d,buffer:g,shader:t,attributes:q.state,uniforms:r,framebuffer:f,extensions:c,timer:k,isBufferArgs:Oa},aa={primTypes:Sa,compareFuncs:Xa,blendFuncs:Ga,blendEquations:X,stencilOps:Pa,glTypes:Ra,orientationType:wb};ha&&(aa.backBuffer=[1029],aa.drawBuffer=J(e.maxDrawbuffers,function(a){return 0===a?[0]:
J(a,function(a){return 36064+a})}));var qa=0;return{next:Fa,current:ra,procs:function(){var a=N(),b=a.proc("poll"),c=a.proc("refresh"),d=a.block();b(d);c(d);var f=a.shared,g=f.gl,h=f.next,k=f.current;d(k,".dirty=false;");K(a,b);K(a,c,null,!0);var m;ea&&(m=a.link(ea));for(var l=0;l<e.maxAttributes;++l){var p=c.def(f.attributes,"[",l,"]"),q=a.cond(p,".buffer");q.then(g,".enableVertexAttribArray(",l,");",g,".bindBuffer(",34962,",",p,".buffer.buffer);",g,".vertexAttribPointer(",l,",",p,".size,",p,".type,",
p,".normalized,",p,".stride,",p,".offset);")["else"](g,".disableVertexAttribArray(",l,");",g,".vertexAttrib4f(",l,",",p,".x,",p,".y,",p,".z,",p,".w);",p,".buffer=null;");c(q);ea&&c(m,".vertexAttribDivisorANGLE(",l,",",p,".divisor);")}Object.keys(sa).forEach(function(e){var f=sa[e],m=d.def(h,".",e),l=a.block();l("if(",m,"){",g,".enable(",f,")}else{",g,".disable(",f,")}",k,".",e,"=",m,";");c(l);b("if(",m,"!==",k,".",e,"){",l,"}")});Object.keys(ta).forEach(function(e){var f=ta[e],m=ra[e],l,p,q=a.block();
q(g,".",f,"(");pa(m)?(f=m.length,l=a.global.def(h,".",e),p=a.global.def(k,".",e),q(J(f,function(a){return l+"["+a+"]"}),");",J(f,function(a){return p+"["+a+"]="+l+"["+a+"];"}).join("")),b("if(",J(f,function(a){return l+"["+a+"]!=="+p+"["+a+"]"}).join("||"),"){",q,"}")):(l=d.def(h,".",e),p=d.def(k,".",e),q(l,");",k,".",e,"=",l,";"),b("if(",l,"!==",p,"){",q,"}"));c(q)});return a.compile()}(),compile:function(a,b,c,d,e){var f=N();f.stats=f.link(e);Object.keys(b["static"]).forEach(function(a){ja(f,b,
a)});Ub.forEach(function(b){ja(f,a,b)});c=A(a,b,c,d,f);da(f,c);ia(f,c);ka(f,c);return f.compile()}}}function yb(a,b){for(var c=0;c<a.length;++c)if(a[c]===b)return c;return-1}var E=function(a,b){for(var c=Object.keys(b),e=0;e<c.length;++e)a[c[e]]=b[c[e]];return a},Ab=0,la={DynamicVariable:aa,define:function(a,b){return new aa(a,Za(b+""))},isDynamic:function(a){return"function"===typeof a&&!a._reglType||a instanceof aa},unbox:function(a,b){return"function"===typeof a?new aa(0,a):a},accessor:Za},Ya=
{next:"function"===typeof requestAnimationFrame?function(a){return requestAnimationFrame(a)}:function(a){return setTimeout(a,16)},cancel:"function"===typeof cancelAnimationFrame?function(a){return cancelAnimationFrame(a)}:clearTimeout},zb="undefined"!==typeof performance&&performance.now?function(){return performance.now()}:function(){return+new Date},x=cb();x.zero=cb();var Vb=function(a,b){var c=1;b.ext_texture_filter_anisotropic&&(c=a.getParameter(34047));var e=1,g=1;b.webgl_draw_buffers&&(e=a.getParameter(34852),
g=a.getParameter(36063));var d=!!b.oes_texture_float;if(d){d=a.createTexture();a.bindTexture(3553,d);a.texImage2D(3553,0,6408,1,1,0,6408,5126,null);var p=a.createFramebuffer();a.bindFramebuffer(36160,p);a.framebufferTexture2D(36160,36064,3553,d,0);a.bindTexture(3553,null);if(36053!==a.checkFramebufferStatus(36160))d=!1;else{a.viewport(0,0,1,1);a.clearColor(1,0,0,1);a.clear(16384);var f=x.allocType(5126,4);a.readPixels(0,0,1,1,6408,5126,f);a.getError()?d=!1:(a.deleteFramebuffer(p),a.deleteTexture(d),
d=1===f[0]);x.freeType(f)}}f=!0;"undefined"!==typeof navigator&&(/MSIE/.test(navigator.userAgent)||/Trident\//.test(navigator.appVersion)||/Edge/.test(navigator.userAgent))||(f=a.createTexture(),p=x.allocType(5121,36),a.activeTexture(33984),a.bindTexture(34067,f),a.texImage2D(34069,0,6408,3,3,0,6408,5121,p),x.freeType(p),a.bindTexture(34067,null),a.deleteTexture(f),f=!a.getError());return{colorBits:[a.getParameter(3410),a.getParameter(3411),a.getParameter(3412),a.getParameter(3413)],depthBits:a.getParameter(3414),
stencilBits:a.getParameter(3415),subpixelBits:a.getParameter(3408),extensions:Object.keys(b).filter(function(a){return!!b[a]}),maxAnisotropic:c,maxDrawbuffers:e,maxColorAttachments:g,pointSizeDims:a.getParameter(33901),lineWidthDims:a.getParameter(33902),maxViewportDims:a.getParameter(3386),maxCombinedTextureUnits:a.getParameter(35661),maxCubeMapSize:a.getParameter(34076),maxRenderbufferSize:a.getParameter(34024),maxTextureUnits:a.getParameter(34930),maxTextureSize:a.getParameter(3379),maxAttributes:a.getParameter(34921),
maxVertexUniforms:a.getParameter(36347),maxVertexTextureUnits:a.getParameter(35660),maxVaryingVectors:a.getParameter(36348),maxFragmentUniforms:a.getParameter(36349),glsl:a.getParameter(35724),renderer:a.getParameter(7937),vendor:a.getParameter(7936),version:a.getParameter(7938),readFloat:d,npotTextureCube:f}},M=function(a){return a instanceof Uint8Array||a instanceof Uint16Array||a instanceof Uint32Array||a instanceof Int8Array||a instanceof Int16Array||a instanceof Int32Array||a instanceof Float32Array||
a instanceof Float64Array||a instanceof Uint8ClampedArray},S=function(a){return Object.keys(a).map(function(b){return a[b]})},Ma={shape:function(a){for(var b=[];a.length;a=a[0])b.push(a.length);return b},flatten:function(a,b,c,e){var g=1;if(b.length)for(var d=0;d<b.length;++d)g*=b[d];else g=0;c=e||x.allocType(c,g);switch(b.length){case 0:break;case 1:e=b[0];for(b=0;b<e;++b)c[b]=a[b];break;case 2:e=b[0];b=b[1];for(d=g=0;d<e;++d)for(var p=a[d],f=0;f<b;++f)c[g++]=p[f];break;case 3:db(a,b[0],b[1],b[2],
c,0);break;default:eb(a,b,0,c,0)}return c}},Ia={"[object Int8Array]":5120,"[object Int16Array]":5122,"[object Int32Array]":5124,"[object Uint8Array]":5121,"[object Uint8ClampedArray]":5121,"[object Uint16Array]":5123,"[object Uint32Array]":5125,"[object Float32Array]":5126,"[object Float64Array]":5121,"[object ArrayBuffer]":5121},Ra={int8:5120,int16:5122,int32:5124,uint8:5121,uint16:5123,uint32:5125,"float":5126,float32:5126},jb={dynamic:35048,stream:35040,"static":35044},Qa=Ma.flatten,hb=Ma.shape,
ja=[];ja[5120]=1;ja[5122]=2;ja[5124]=4;ja[5121]=1;ja[5123]=2;ja[5125]=4;ja[5126]=4;var Sa={points:0,point:0,lines:1,line:1,triangles:4,triangle:4,"line loop":2,"line strip":3,"triangle strip":5,"triangle fan":6},lb=new Float32Array(1),Ib=new Uint32Array(lb.buffer),Mb=[9984,9986,9985,9987],La=[0,6409,6410,6407,6408],L={};L[6409]=L[6406]=L[6402]=1;L[34041]=L[6410]=2;L[6407]=L[35904]=3;L[6408]=L[35906]=4;var Ua=Ea("HTMLCanvasElement"),pb=Ea("CanvasRenderingContext2D"),qb=Ea("ImageBitmap"),rb=Ea("HTMLImageElement"),
sb=Ea("HTMLVideoElement"),Jb=Object.keys(Ia).concat([Ua,pb,qb,rb,sb]),qa=[];qa[5121]=1;qa[5126]=4;qa[36193]=2;qa[5123]=2;qa[5125]=4;var z=[];z[32854]=2;z[32855]=2;z[36194]=2;z[34041]=4;z[33776]=.5;z[33777]=.5;z[33778]=1;z[33779]=1;z[35986]=.5;z[35987]=1;z[34798]=1;z[35840]=.5;z[35841]=.25;z[35842]=.5;z[35843]=.25;z[36196]=.5;var Q=[];Q[32854]=2;Q[32855]=2;Q[36194]=2;Q[33189]=2;Q[36168]=1;Q[34041]=4;Q[35907]=4;Q[34836]=16;Q[34842]=8;Q[34843]=6;var Wb=function(a,b,c,e,g){function d(a){this.id=q++;this.refCount=
1;this.renderbuffer=a;this.format=32854;this.height=this.width=0;g.profile&&(this.stats={size:0})}function p(b){var c=b.renderbuffer;a.bindRenderbuffer(36161,null);a.deleteRenderbuffer(c);b.renderbuffer=null;b.refCount=0;delete t[b.id];e.renderbufferCount--}var f={rgba4:32854,rgb565:36194,"rgb5 a1":32855,depth:33189,stencil:36168,"depth stencil":34041};b.ext_srgb&&(f.srgba=35907);b.ext_color_buffer_half_float&&(f.rgba16f=34842,f.rgb16f=34843);b.webgl_color_buffer_float&&(f.rgba32f=34836);var r=[];
Object.keys(f).forEach(function(a){r[f[a]]=a});var q=0,t={};d.prototype.decRef=function(){0>=--this.refCount&&p(this)};g.profile&&(e.getTotalRenderbufferSize=function(){var a=0;Object.keys(t).forEach(function(b){a+=t[b].stats.size});return a});return{create:function(b,c){function k(b,c){var d=0,e=0,m=32854;"object"===typeof b&&b?("shape"in b?(e=b.shape,d=e[0]|0,e=e[1]|0):("radius"in b&&(d=e=b.radius|0),"width"in b&&(d=b.width|0),"height"in b&&(e=b.height|0)),"format"in b&&(m=f[b.format])):"number"===
typeof b?(d=b|0,e="number"===typeof c?c|0:d):b||(d=e=1);if(d!==h.width||e!==h.height||m!==h.format)return k.width=h.width=d,k.height=h.height=e,h.format=m,a.bindRenderbuffer(36161,h.renderbuffer),a.renderbufferStorage(36161,m,d,e),g.profile&&(h.stats.size=Q[h.format]*h.width*h.height),k.format=r[h.format],k}var h=new d(a.createRenderbuffer());t[h.id]=h;e.renderbufferCount++;k(b,c);k.resize=function(b,c){var d=b|0,e=c|0||d;if(d===h.width&&e===h.height)return k;k.width=h.width=d;k.height=h.height=e;
a.bindRenderbuffer(36161,h.renderbuffer);a.renderbufferStorage(36161,h.format,d,e);g.profile&&(h.stats.size=Q[h.format]*h.width*h.height);return k};k._reglType="renderbuffer";k._renderbuffer=h;g.profile&&(k.stats=h.stats);k.destroy=function(){h.decRef()};return k},clear:function(){S(t).forEach(p)},restore:function(){S(t).forEach(function(b){b.renderbuffer=a.createRenderbuffer();a.bindRenderbuffer(36161,b.renderbuffer);a.renderbufferStorage(36161,b.format,b.width,b.height)});a.bindRenderbuffer(36161,
null)}}},Wa=[];Wa[6408]=4;Wa[6407]=3;var Na=[];Na[5121]=1;Na[5126]=4;Na[36193]=2;var Da=["x","y","z","w"],Ub="blend.func blend.equation stencil.func stencil.opFront stencil.opBack sample.coverage viewport scissor.box polygonOffset.offset".split(" "),Ga={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},Xa={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},Pa={0:0,zero:0,keep:7680,replace:7681,increment:7682,decrement:7683,"increment wrap":34055,"decrement wrap":34056,invert:5386},wb={cw:2304,ccw:2305},xb=new Z(!1,!1,!1,function(){}),Xb=function(a,b){function c(){this.endQueryIndex=this.startQueryIndex=-1;this.sum=0;this.stats=
null}function e(a,b,d){var e=p.pop()||new c;e.startQueryIndex=a;e.endQueryIndex=b;e.sum=0;e.stats=d;f.push(e)}if(!b.ext_disjoint_timer_query)return null;var g=[],d=[],p=[],f=[],r=[],q=[];return{beginQuery:function(a){var c=g.pop()||b.ext_disjoint_timer_query.createQueryEXT();b.ext_disjoint_timer_query.beginQueryEXT(35007,c);d.push(c);e(d.length-1,d.length,a)},endQuery:function(){b.ext_disjoint_timer_query.endQueryEXT(35007)},pushScopeStats:e,update:function(){var a,c;a=d.length;if(0!==a){q.length=
Math.max(q.length,a+1);r.length=Math.max(r.length,a+1);r[0]=0;var e=q[0]=0;for(c=a=0;c<d.length;++c){var k=d[c];b.ext_disjoint_timer_query.getQueryObjectEXT(k,34919)?(e+=b.ext_disjoint_timer_query.getQueryObjectEXT(k,34918),g.push(k)):d[a++]=k;r[c+1]=e;q[c+1]=a}d.length=a;for(c=a=0;c<f.length;++c){var e=f[c],h=e.startQueryIndex,k=e.endQueryIndex;e.sum+=r[k]-r[h];h=q[h];k=q[k];k===h?(e.stats.gpuTime+=e.sum/1E6,p.push(e)):(e.startQueryIndex=h,e.endQueryIndex=k,f[a++]=e)}f.length=a}},getNumPendingQueries:function(){return d.length},
clear:function(){g.push.apply(g,d);for(var a=0;a<g.length;a++)b.ext_disjoint_timer_query.deleteQueryEXT(g[a]);d.length=0;g.length=0},restore:function(){d.length=0;g.length=0}}};return function(a){function b(){if(0===G.length)B&&B.update(),ca=null;else{ca=Ya.next(b);t();for(var a=G.length-1;0<=a;--a){var c=G[a];c&&c(O,null,0)}k.flush();B&&B.update()}}function c(){!ca&&0<G.length&&(ca=Ya.next(b))}function e(){ca&&(Ya.cancel(b),ca=null)}function g(a){a.preventDefault();e();U.forEach(function(a){a()})}
function d(a){k.getError();l.restore();Q.restore();F.restore();A.restore();M.restore();K.restore();B&&B.restore();V.procs.refresh();c();W.forEach(function(a){a()})}function p(a){function b(a){var c={},d={};Object.keys(a).forEach(function(b){var e=a[b];la.isDynamic(e)?d[b]=la.unbox(e,b):c[b]=e});return{dynamic:d,"static":c}}function c(a){for(;m.length<a;)m.push(null);return m}var d=b(a.context||{}),e=b(a.uniforms||{}),f=b(a.attributes||{}),g=b(function(a){function b(a){if(a in c){var d=c[a];delete c[a];
Object.keys(d).forEach(function(b){c[a+"."+b]=d[b]})}}var c=E({},a);delete c.uniforms;delete c.attributes;delete c.context;"stencil"in c&&c.stencil.op&&(c.stencil.opBack=c.stencil.opFront=c.stencil.op,delete c.stencil.op);b("blend");b("depth");b("cull");b("stencil");b("polygonOffset");b("scissor");b("sample");return c}(a));a={gpuTime:0,cpuTime:0,count:0};var d=V.compile(g,f,e,d,a),h=d.draw,k=d.batch,l=d.scope,m=[];return E(function(a,b){var d;if("function"===typeof a)return l.call(this,null,a,0);
if("function"===typeof b)if("number"===typeof a)for(d=0;d<a;++d)l.call(this,null,b,d);else if(Array.isArray(a))for(d=0;d<a.length;++d)l.call(this,a[d],b,d);else return l.call(this,a,b,0);else if("number"===typeof a){if(0<a)return k.call(this,c(a|0),a|0)}else if(Array.isArray(a)){if(a.length)return k.call(this,a,a.length)}else return h.call(this,a)},{stats:a})}function f(a,b){var c=0;V.procs.poll();var d=b.color;d&&(k.clearColor(+d[0]||0,+d[1]||0,+d[2]||0,+d[3]||0),c|=16384);"depth"in b&&(k.clearDepth(+b.depth),
c|=256);"stencil"in b&&(k.clearStencil(b.stencil|0),c|=1024);k.clear(c)}function r(a){G.push(a);c();return{cancel:function(){function b(){var a=yb(G,b);G[a]=G[G.length-1];--G.length;0>=G.length&&e()}var c=yb(G,a);G[c]=b}}}function q(){var a=S.viewport,b=S.scissor_box;a[0]=a[1]=b[0]=b[1]=0;O.viewportWidth=O.framebufferWidth=O.drawingBufferWidth=a[2]=b[2]=k.drawingBufferWidth;O.viewportHeight=O.framebufferHeight=O.drawingBufferHeight=a[3]=b[3]=k.drawingBufferHeight}function t(){O.tick+=1;O.time=z();
q();V.procs.poll()}function m(){q();V.procs.refresh();B&&B.update()}function z(){return(zb()-D)/1E3}a=Eb(a);if(!a)return null;var k=a.gl,h=k.getContextAttributes();k.isContextLost();var l=Fb(k,a);if(!l)return null;var u=Bb(),v={bufferCount:0,elementsCount:0,framebufferCount:0,shaderCount:0,textureCount:0,cubeCount:0,renderbufferCount:0,maxTextureUnits:0},x=l.extensions,B=Xb(k,x),D=zb(),J=k.drawingBufferWidth,P=k.drawingBufferHeight,O={tick:0,time:0,viewportWidth:J,viewportHeight:P,framebufferWidth:J,
framebufferHeight:P,drawingBufferWidth:J,drawingBufferHeight:P,pixelRatio:a.pixelRatio},R=Vb(k,x),J=Pb(k,x,R,u),F=Gb(k,v,a,J),T=Hb(k,x,F,v),Q=Qb(k,u,v,a),A=Kb(k,x,R,function(){V.procs.poll()},O,v,a),M=Wb(k,x,R,v,a),K=Ob(k,x,R,A,M,v),V=Tb(k,u,x,R,F,T,A,K,{},J,Q,{elements:null,primitive:4,count:-1,offset:0,instances:-1},O,B,a),u=Rb(k,K,V.procs.poll,O,h,x,R),S=V.next,L=k.canvas,G=[],U=[],W=[],Z=[a.onDestroy],ca=null;L&&(L.addEventListener("webglcontextlost",g,!1),L.addEventListener("webglcontextrestored",
d,!1));var aa=K.setFBO=p({framebuffer:la.define.call(null,1,"framebuffer")});m();h=E(p,{clear:function(a){if("framebuffer"in a)if(a.framebuffer&&"framebufferCube"===a.framebuffer_reglType)for(var b=0;6>b;++b)aa(E({framebuffer:a.framebuffer.faces[b]},a),f);else aa(a,f);else f(null,a)},prop:la.define.bind(null,1),context:la.define.bind(null,2),"this":la.define.bind(null,3),draw:p({}),buffer:function(a){return F.create(a,34962,!1,!1)},elements:function(a){return T.create(a,!1)},texture:A.create2D,cube:A.createCube,
renderbuffer:M.create,framebuffer:K.create,framebufferCube:K.createCube,attributes:h,frame:r,on:function(a,b){var c;switch(a){case "frame":return r(b);case "lost":c=U;break;case "restore":c=W;break;case "destroy":c=Z}c.push(b);return{cancel:function(){for(var a=0;a<c.length;++a)if(c[a]===b){c[a]=c[c.length-1];c.pop();break}}}},limits:R,hasExtension:function(a){return 0<=R.extensions.indexOf(a.toLowerCase())},read:u,destroy:function(){G.length=0;e();L&&(L.removeEventListener("webglcontextlost",g),
L.removeEventListener("webglcontextrestored",d));Q.clear();K.clear();M.clear();A.clear();T.clear();F.clear();B&&B.clear();Z.forEach(function(a){a()})},_gl:k,_refresh:m,poll:function(){t();B&&B.update()},now:z,stats:v});a.onDone(null,h);return h}});

47349
lib/three.js

File diff suppressed because one or more lines are too long