mirror of
https://github.com/Rezmason/matrix.git
synced 2026-04-18 22:29:28 -07:00
Ran all the JS through prettier.
This commit is contained in:
@@ -2,10 +2,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<title>Matrix digital rain</title>
|
<title>Matrix digital rain</title>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta
|
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
|
||||||
name="viewport"
|
|
||||||
content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"
|
|
||||||
/>
|
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
background: black;
|
background: black;
|
||||||
|
|||||||
@@ -1,39 +1,24 @@
|
|||||||
import {
|
import { loadText, extractEntries, makePassFBO, makePyramid, resizePyramid, makePass } from "./utils.js";
|
||||||
loadText,
|
|
||||||
extractEntries,
|
|
||||||
makePassFBO,
|
|
||||||
makePyramid,
|
|
||||||
resizePyramid,
|
|
||||||
makePass
|
|
||||||
} from "./utils.js";
|
|
||||||
|
|
||||||
// The bloom pass is basically an added high-pass blur.
|
// The bloom pass is basically an added high-pass blur.
|
||||||
|
|
||||||
const pyramidHeight = 5;
|
const pyramidHeight = 5;
|
||||||
const levelStrengths = Array(pyramidHeight)
|
const levelStrengths = Array(pyramidHeight)
|
||||||
.fill()
|
.fill()
|
||||||
.map((_, index) =>
|
.map((_, index) => Math.pow(index / (pyramidHeight * 2) + 0.5, 1 / 3).toPrecision(5))
|
||||||
Math.pow(index / (pyramidHeight * 2) + 0.5, 1 / 3).toPrecision(5)
|
|
||||||
)
|
|
||||||
.reverse();
|
.reverse();
|
||||||
|
|
||||||
export default (regl, config, inputs) => {
|
export default (regl, config, inputs) => {
|
||||||
|
|
||||||
const enabled = config.bloomSize > 0 && config.bloomStrength > 0;
|
const enabled = config.bloomSize > 0 && config.bloomStrength > 0;
|
||||||
|
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
return makePass(
|
return makePass({
|
||||||
{
|
|
||||||
primary: inputs.primary,
|
primary: inputs.primary,
|
||||||
bloom: makePassFBO(regl)
|
bloom: makePassFBO(regl),
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const uniforms = extractEntries(config, [
|
const uniforms = extractEntries(config, ["bloomStrength", "highPassThreshold"]);
|
||||||
"bloomStrength",
|
|
||||||
"highPassThreshold"
|
|
||||||
]);
|
|
||||||
|
|
||||||
const highPassPyramid = makePyramid(regl, pyramidHeight, config.useHalfFloat);
|
const highPassPyramid = makePyramid(regl, pyramidHeight, config.useHalfFloat);
|
||||||
const hBlurPyramid = makePyramid(regl, pyramidHeight, config.useHalfFloat);
|
const hBlurPyramid = makePyramid(regl, pyramidHeight, config.useHalfFloat);
|
||||||
@@ -47,9 +32,9 @@ export default (regl, config, inputs) => {
|
|||||||
frag: regl.prop("frag"),
|
frag: regl.prop("frag"),
|
||||||
uniforms: {
|
uniforms: {
|
||||||
...uniforms,
|
...uniforms,
|
||||||
tex: regl.prop("tex")
|
tex: regl.prop("tex"),
|
||||||
},
|
},
|
||||||
framebuffer: regl.prop("fbo")
|
framebuffer: regl.prop("fbo"),
|
||||||
});
|
});
|
||||||
|
|
||||||
// A 2D gaussian blur is just a 1D blur done horizontally, then done vertically.
|
// A 2D gaussian blur is just a 1D blur done horizontally, then done vertically.
|
||||||
@@ -64,9 +49,9 @@ export default (regl, config, inputs) => {
|
|||||||
tex: regl.prop("tex"),
|
tex: regl.prop("tex"),
|
||||||
direction: regl.prop("direction"),
|
direction: regl.prop("direction"),
|
||||||
height: regl.context("viewportWidth"),
|
height: regl.context("viewportWidth"),
|
||||||
width: regl.context("viewportHeight")
|
width: regl.context("viewportHeight"),
|
||||||
},
|
},
|
||||||
framebuffer: regl.prop("fbo")
|
framebuffer: regl.prop("fbo"),
|
||||||
});
|
});
|
||||||
|
|
||||||
// The pyramid of textures gets flattened onto the source texture.
|
// The pyramid of textures gets flattened onto the source texture.
|
||||||
@@ -74,34 +59,25 @@ export default (regl, config, inputs) => {
|
|||||||
frag: `
|
frag: `
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
varying vec2 vUV;
|
varying vec2 vUV;
|
||||||
${vBlurPyramid
|
${vBlurPyramid.map((_, index) => `uniform sampler2D pyr_${index};`).join("\n")}
|
||||||
.map((_, index) => `uniform sampler2D pyr_${index};`)
|
|
||||||
.join("\n")}
|
|
||||||
uniform float bloomStrength;
|
uniform float bloomStrength;
|
||||||
void main() {
|
void main() {
|
||||||
vec4 total = vec4(0.);
|
vec4 total = vec4(0.);
|
||||||
${vBlurPyramid
|
${vBlurPyramid.map((_, index) => `total += texture2D(pyr_${index}, vUV) * ${levelStrengths[index]};`).join("\n")}
|
||||||
.map(
|
|
||||||
(_, index) =>
|
|
||||||
`total += texture2D(pyr_${index}, vUV) * ${levelStrengths[index]};`
|
|
||||||
)
|
|
||||||
.join("\n")}
|
|
||||||
gl_FragColor = total * bloomStrength;
|
gl_FragColor = total * bloomStrength;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
uniforms: {
|
uniforms: {
|
||||||
...uniforms,
|
...uniforms,
|
||||||
...Object.fromEntries(
|
...Object.fromEntries(vBlurPyramid.map((fbo, index) => [`pyr_${index}`, fbo])),
|
||||||
vBlurPyramid.map((fbo, index) => [`pyr_${index}`, fbo])
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
framebuffer: output
|
framebuffer: output,
|
||||||
});
|
});
|
||||||
|
|
||||||
return makePass(
|
return makePass(
|
||||||
{
|
{
|
||||||
primary: inputs.primary,
|
primary: inputs.primary,
|
||||||
bloom: output
|
bloom: output,
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
for (let i = 0; i < pyramidHeight; i++) {
|
for (let i = 0; i < pyramidHeight; i++) {
|
||||||
|
|||||||
79
js/config.js
79
js/config.js
@@ -2,18 +2,18 @@ const fonts = {
|
|||||||
coptic: {
|
coptic: {
|
||||||
glyphTexURL: "coptic_msdf.png",
|
glyphTexURL: "coptic_msdf.png",
|
||||||
glyphSequenceLength: 32,
|
glyphSequenceLength: 32,
|
||||||
glyphTextureColumns: 8
|
glyphTextureColumns: 8,
|
||||||
},
|
},
|
||||||
gothic: {
|
gothic: {
|
||||||
glyphTexURL: "gothic_msdf.png",
|
glyphTexURL: "gothic_msdf.png",
|
||||||
glyphSequenceLength: 27,
|
glyphSequenceLength: 27,
|
||||||
glyphTextureColumns: 8
|
glyphTextureColumns: 8,
|
||||||
},
|
},
|
||||||
matrixcode: {
|
matrixcode: {
|
||||||
glyphTexURL: "matrixcode_msdf.png",
|
glyphTexURL: "matrixcode_msdf.png",
|
||||||
glyphSequenceLength: 57,
|
glyphSequenceLength: 57,
|
||||||
glyphTextureColumns: 8
|
glyphTextureColumns: 8,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaults = {
|
const defaults = {
|
||||||
@@ -48,7 +48,7 @@ const defaults = {
|
|||||||
{ hsl: [0.3, 0.9, 0.0], at: 0.0 },
|
{ hsl: [0.3, 0.9, 0.0], at: 0.0 },
|
||||||
{ hsl: [0.3, 0.9, 0.2], at: 0.2 },
|
{ hsl: [0.3, 0.9, 0.2], at: 0.2 },
|
||||||
{ hsl: [0.3, 0.9, 0.7], at: 0.7 },
|
{ hsl: [0.3, 0.9, 0.7], at: 0.7 },
|
||||||
{ hsl: [0.3, 0.9, 0.8], at: 0.8 }
|
{ hsl: [0.3, 0.9, 0.8], at: 0.8 },
|
||||||
],
|
],
|
||||||
raindropLength: 1,
|
raindropLength: 1,
|
||||||
slant: 0,
|
slant: 0,
|
||||||
@@ -59,7 +59,7 @@ const defaults = {
|
|||||||
const versions = {
|
const versions = {
|
||||||
classic: {
|
classic: {
|
||||||
...defaults,
|
...defaults,
|
||||||
...fonts.matrixcode
|
...fonts.matrixcode,
|
||||||
},
|
},
|
||||||
operator: {
|
operator: {
|
||||||
...defaults,
|
...defaults,
|
||||||
@@ -80,9 +80,9 @@ const versions = {
|
|||||||
paletteEntries: [
|
paletteEntries: [
|
||||||
{ hsl: [0.4, 0.8, 0.0], at: 0.0 },
|
{ hsl: [0.4, 0.8, 0.0], at: 0.0 },
|
||||||
{ hsl: [0.4, 0.8, 0.5], at: 0.5 },
|
{ hsl: [0.4, 0.8, 0.5], at: 0.5 },
|
||||||
{ hsl: [0.4, 0.8, 1.0], at: 1.0 }
|
{ hsl: [0.4, 0.8, 1.0], at: 1.0 },
|
||||||
],
|
],
|
||||||
raindropLength: 1.5
|
raindropLength: 1.5,
|
||||||
},
|
},
|
||||||
nightmare: {
|
nightmare: {
|
||||||
...defaults,
|
...defaults,
|
||||||
@@ -97,10 +97,10 @@ const versions = {
|
|||||||
{ hsl: [0.0, 1.0, 0.2], at: 0.2 },
|
{ hsl: [0.0, 1.0, 0.2], at: 0.2 },
|
||||||
{ hsl: [0.0, 1.0, 0.4], at: 0.4 },
|
{ hsl: [0.0, 1.0, 0.4], at: 0.4 },
|
||||||
{ hsl: [0.1, 1.0, 0.7], at: 0.7 },
|
{ hsl: [0.1, 1.0, 0.7], at: 0.7 },
|
||||||
{ hsl: [0.2, 1.0, 1.0], at: 1.0 }
|
{ hsl: [0.2, 1.0, 1.0], at: 1.0 },
|
||||||
],
|
],
|
||||||
raindropLength: 0.6,
|
raindropLength: 0.6,
|
||||||
slant: (22.5 * Math.PI) / 180
|
slant: (22.5 * Math.PI) / 180,
|
||||||
},
|
},
|
||||||
paradise: {
|
paradise: {
|
||||||
...defaults,
|
...defaults,
|
||||||
@@ -120,9 +120,9 @@ const versions = {
|
|||||||
{ hsl: [0.0, 0.8, 0.3], at: 0.3 },
|
{ hsl: [0.0, 0.8, 0.3], at: 0.3 },
|
||||||
{ hsl: [0.1, 0.8, 0.5], at: 0.5 },
|
{ hsl: [0.1, 0.8, 0.5], at: 0.5 },
|
||||||
{ hsl: [0.1, 1.0, 0.6], at: 0.6 },
|
{ hsl: [0.1, 1.0, 0.6], at: 0.6 },
|
||||||
{ hsl: [0.1, 1.0, 0.9], at: 0.9 }
|
{ hsl: [0.1, 1.0, 0.9], at: 0.9 },
|
||||||
],
|
],
|
||||||
raindropLength: 0.4
|
raindropLength: 0.4,
|
||||||
},
|
},
|
||||||
resurrections: {
|
resurrections: {
|
||||||
...defaults,
|
...defaults,
|
||||||
@@ -133,49 +133,48 @@ const versions = {
|
|||||||
volumetric: true,
|
volumetric: true,
|
||||||
density: 1.5,
|
density: 1.5,
|
||||||
fallSpeed: 1.2,
|
fallSpeed: 1.2,
|
||||||
raindropLength:1.25
|
raindropLength: 1.25,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
versions.throwback = versions.operator;
|
versions.throwback = versions.operator;
|
||||||
versions["1999"] = versions.classic;
|
versions["1999"] = versions.classic;
|
||||||
|
|
||||||
const range = (f, min = -Infinity, max = Infinity) =>
|
const range = (f, min = -Infinity, max = Infinity) => Math.max(min, Math.min(max, f));
|
||||||
Math.max(min, Math.min(max, f));
|
const nullNaN = (f) => (isNaN(f) ? null : f);
|
||||||
const nullNaN = f => (isNaN(f) ? null : f);
|
|
||||||
|
|
||||||
const paramMapping = {
|
const paramMapping = {
|
||||||
version: { key: "version", parser: s => s },
|
version: { key: "version", parser: (s) => s },
|
||||||
effect: { key: "effect", parser: s => s },
|
effect: { key: "effect", parser: (s) => s },
|
||||||
width: { key: "numColumns", parser: s => nullNaN(parseInt(s)) },
|
width: { key: "numColumns", parser: (s) => nullNaN(parseInt(s)) },
|
||||||
numColumns: { key: "numColumns", parser: s => nullNaN(parseInt(s)) },
|
numColumns: { key: "numColumns", parser: (s) => nullNaN(parseInt(s)) },
|
||||||
density: { key: "density", parser: s => nullNaN(range(parseFloat(s), 0)) },
|
density: { key: "density", parser: (s) => nullNaN(range(parseFloat(s), 0)) },
|
||||||
resolution: { key: "resolution", parser: s => nullNaN(parseFloat(s)) },
|
resolution: { key: "resolution", parser: (s) => nullNaN(parseFloat(s)) },
|
||||||
animationSpeed: {
|
animationSpeed: {
|
||||||
key: "animationSpeed",
|
key: "animationSpeed",
|
||||||
parser: s => nullNaN(parseFloat(s))
|
parser: (s) => nullNaN(parseFloat(s)),
|
||||||
},
|
},
|
||||||
forwardSpeed: {
|
forwardSpeed: {
|
||||||
key: "forwardSpeed",
|
key: "forwardSpeed",
|
||||||
parser: s => nullNaN(parseFloat(s))
|
parser: (s) => nullNaN(parseFloat(s)),
|
||||||
},
|
},
|
||||||
cycleSpeed: { key: "cycleSpeed", parser: s => nullNaN(parseFloat(s)) },
|
cycleSpeed: { key: "cycleSpeed", parser: (s) => nullNaN(parseFloat(s)) },
|
||||||
fallSpeed: { key: "fallSpeed", parser: s => nullNaN(parseFloat(s)) },
|
fallSpeed: { key: "fallSpeed", parser: (s) => nullNaN(parseFloat(s)) },
|
||||||
raindropLength: {
|
raindropLength: {
|
||||||
key: "raindropLength",
|
key: "raindropLength",
|
||||||
parser: s => nullNaN(parseFloat(s))
|
parser: (s) => nullNaN(parseFloat(s)),
|
||||||
},
|
},
|
||||||
slant: {
|
slant: {
|
||||||
key: "slant",
|
key: "slant",
|
||||||
parser: s => nullNaN((parseFloat(s) * Math.PI) / 180)
|
parser: (s) => nullNaN((parseFloat(s) * Math.PI) / 180),
|
||||||
},
|
},
|
||||||
bloomSize: {
|
bloomSize: {
|
||||||
key: "bloomSize",
|
key: "bloomSize",
|
||||||
parser: s => nullNaN(range(parseFloat(s), 0, 1))
|
parser: (s) => nullNaN(range(parseFloat(s), 0, 1)),
|
||||||
},
|
},
|
||||||
url: { key: "bgURL", parser: s => s },
|
url: { key: "bgURL", parser: (s) => s },
|
||||||
stripeColors: { key: "stripeColors", parser: s => s },
|
stripeColors: { key: "stripeColors", parser: (s) => s },
|
||||||
backgroundColor: { key: "backgroundColor", parser: s => s.split(",").map(parseFloat) },
|
backgroundColor: { key: "backgroundColor", parser: (s) => s.split(",").map(parseFloat) },
|
||||||
volumetric: { key: "volumetric", parser: s => s.toLowerCase().includes("true") }
|
volumetric: { key: "volumetric", parser: (s) => s.toLowerCase().includes("true") },
|
||||||
};
|
};
|
||||||
paramMapping.dropLength = paramMapping.raindropLength;
|
paramMapping.dropLength = paramMapping.raindropLength;
|
||||||
paramMapping.angle = paramMapping.slant;
|
paramMapping.angle = paramMapping.slant;
|
||||||
@@ -185,20 +184,14 @@ export default (searchString, make1DTexture) => {
|
|||||||
const urlParams = Object.fromEntries(
|
const urlParams = Object.fromEntries(
|
||||||
Array.from(new URLSearchParams(searchString).entries())
|
Array.from(new URLSearchParams(searchString).entries())
|
||||||
.filter(([key]) => key in paramMapping)
|
.filter(([key]) => key in paramMapping)
|
||||||
.map(([key, value]) => [
|
.map(([key, value]) => [paramMapping[key].key, paramMapping[key].parser(value)])
|
||||||
paramMapping[key].key,
|
|
||||||
paramMapping[key].parser(value)
|
|
||||||
])
|
|
||||||
.filter(([_, value]) => value != null)
|
.filter(([_, value]) => value != null)
|
||||||
);
|
);
|
||||||
|
|
||||||
const version =
|
const version = urlParams.version in versions ? versions[urlParams.version] : versions.classic;
|
||||||
urlParams.version in versions
|
|
||||||
? versions[urlParams.version]
|
|
||||||
: versions.classic;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...version,
|
...version,
|
||||||
...urlParams
|
...urlParams,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { loadImage, loadText, makePassFBO, makePass } from "./utils.js";
|
import { loadImage, loadText, makePassFBO, makePass } from "./utils.js";
|
||||||
|
|
||||||
const defaultBGURL =
|
const defaultBGURL = "https://upload.wikimedia.org/wikipedia/commons/0/0a/Flammarion_Colored.jpg";
|
||||||
"https://upload.wikimedia.org/wikipedia/commons/0/0a/Flammarion_Colored.jpg";
|
|
||||||
|
|
||||||
export default (regl, config, inputs) => {
|
export default (regl, config, inputs) => {
|
||||||
const output = makePassFBO(regl, config.useHalfFloat);
|
const output = makePassFBO(regl, config.useHalfFloat);
|
||||||
@@ -13,13 +12,13 @@ export default (regl, config, inputs) => {
|
|||||||
uniforms: {
|
uniforms: {
|
||||||
backgroundTex: background.texture,
|
backgroundTex: background.texture,
|
||||||
tex: inputs.primary,
|
tex: inputs.primary,
|
||||||
bloomTex: inputs.bloom
|
bloomTex: inputs.bloom,
|
||||||
},
|
},
|
||||||
framebuffer: output
|
framebuffer: output,
|
||||||
});
|
});
|
||||||
return makePass(
|
return makePass(
|
||||||
{
|
{
|
||||||
primary: output
|
primary: output,
|
||||||
},
|
},
|
||||||
() => render({ frag: imagePassFrag.text() }),
|
() => render({ frag: imagePassFrag.text() }),
|
||||||
null,
|
null,
|
||||||
|
|||||||
32
js/main.js
32
js/main.js
@@ -9,19 +9,15 @@ import makeResurrectionPass from "./resurrectionPass.js";
|
|||||||
|
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
document.body.appendChild(canvas);
|
document.body.appendChild(canvas);
|
||||||
document.addEventListener("touchmove", e => e.preventDefault(), {
|
document.addEventListener("touchmove", (e) => e.preventDefault(), {
|
||||||
passive: false
|
passive: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const regl = createREGL({
|
const regl = createREGL({
|
||||||
canvas,
|
canvas,
|
||||||
extensions: ["OES_texture_half_float", "OES_texture_half_float_linear"],
|
extensions: ["OES_texture_half_float", "OES_texture_half_float_linear"],
|
||||||
// These extensions are also needed, but Safari misreports that they are missing
|
// These extensions are also needed, but Safari misreports that they are missing
|
||||||
optionalExtensions: [
|
optionalExtensions: ["EXT_color_buffer_half_float", "WEBGL_color_buffer_float", "OES_standard_derivatives"],
|
||||||
"EXT_color_buffer_half_float",
|
|
||||||
"WEBGL_color_buffer_float",
|
|
||||||
"OES_standard_derivatives"
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const effects = {
|
const effects = {
|
||||||
@@ -32,7 +28,7 @@ const effects = {
|
|||||||
pride: makeStripePass,
|
pride: makeStripePass,
|
||||||
image: makeImagePass,
|
image: makeImagePass,
|
||||||
resurrection: makeResurrectionPass,
|
resurrection: makeResurrectionPass,
|
||||||
resurrections: makeResurrectionPass
|
resurrections: makeResurrectionPass,
|
||||||
};
|
};
|
||||||
|
|
||||||
const config = makeConfig(window.location.search);
|
const config = makeConfig(window.location.search);
|
||||||
@@ -51,28 +47,16 @@ const dimensions = { width: 1, height: 1 };
|
|||||||
document.body.onload = async () => {
|
document.body.onload = async () => {
|
||||||
// All this takes place in a full screen quad.
|
// All this takes place in a full screen quad.
|
||||||
const fullScreenQuad = makeFullScreenQuad(regl);
|
const fullScreenQuad = makeFullScreenQuad(regl);
|
||||||
const pipeline = makePipeline(
|
const pipeline = makePipeline([makeMatrixRenderer, effect === "none" ? null : makeBloomPass, effects[effect]], (p) => p.outputs, regl, config);
|
||||||
[
|
|
||||||
makeMatrixRenderer,
|
|
||||||
effect === "none" ? null : makeBloomPass,
|
|
||||||
effects[effect]
|
|
||||||
],
|
|
||||||
p => p.outputs,
|
|
||||||
regl,
|
|
||||||
config
|
|
||||||
);
|
|
||||||
const drawToScreen = regl({
|
const drawToScreen = regl({
|
||||||
uniforms: {
|
uniforms: {
|
||||||
tex: pipeline[pipeline.length - 1].outputs.primary
|
tex: pipeline[pipeline.length - 1].outputs.primary,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
await Promise.all(pipeline.map(({ ready }) => ready));
|
await Promise.all(pipeline.map(({ ready }) => ready));
|
||||||
const tick = regl.frame(({ viewportWidth, viewportHeight }) => {
|
const tick = regl.frame(({ viewportWidth, viewportHeight }) => {
|
||||||
// tick.cancel();
|
// tick.cancel();
|
||||||
if (
|
if (dimensions.width !== viewportWidth || dimensions.height !== viewportHeight) {
|
||||||
dimensions.width !== viewportWidth ||
|
|
||||||
dimensions.height !== viewportHeight
|
|
||||||
) {
|
|
||||||
dimensions.width = viewportWidth;
|
dimensions.width = viewportWidth;
|
||||||
dimensions.height = viewportHeight;
|
dimensions.height = viewportHeight;
|
||||||
for (const step of pipeline) {
|
for (const step of pipeline) {
|
||||||
|
|||||||
@@ -15,16 +15,14 @@ const makePalette = (regl, entries) => {
|
|||||||
const sortedEntries = entries
|
const sortedEntries = entries
|
||||||
.slice()
|
.slice()
|
||||||
.sort((e1, e2) => e1.at - e2.at)
|
.sort((e1, e2) => e1.at - e2.at)
|
||||||
.map(entry => ({
|
.map((entry) => ({
|
||||||
rgb: colorToRGB(entry.hsl),
|
rgb: colorToRGB(entry.hsl),
|
||||||
arrayIndex: Math.floor(
|
arrayIndex: Math.floor(Math.max(Math.min(1, entry.at), 0) * (PALETTE_SIZE - 1)),
|
||||||
Math.max(Math.min(1, entry.at), 0) * (PALETTE_SIZE - 1)
|
|
||||||
)
|
|
||||||
}));
|
}));
|
||||||
sortedEntries.unshift({ rgb: sortedEntries[0].rgb, arrayIndex: 0 });
|
sortedEntries.unshift({ rgb: sortedEntries[0].rgb, arrayIndex: 0 });
|
||||||
sortedEntries.push({
|
sortedEntries.push({
|
||||||
rgb: sortedEntries[sortedEntries.length - 1].rgb,
|
rgb: sortedEntries[sortedEntries.length - 1].rgb,
|
||||||
arrayIndex: PALETTE_SIZE - 1
|
arrayIndex: PALETTE_SIZE - 1,
|
||||||
});
|
});
|
||||||
sortedEntries.forEach((entry, index) => {
|
sortedEntries.forEach((entry, index) => {
|
||||||
paletteColors[entry.arrayIndex] = entry.rgb.slice();
|
paletteColors[entry.arrayIndex] = entry.rgb.slice();
|
||||||
@@ -36,7 +34,7 @@ const makePalette = (regl, entries) => {
|
|||||||
paletteColors[entry.arrayIndex + i] = [
|
paletteColors[entry.arrayIndex + i] = [
|
||||||
entry.rgb[0] * (1 - ratio) + nextEntry.rgb[0] * ratio,
|
entry.rgb[0] * (1 - ratio) + nextEntry.rgb[0] * ratio,
|
||||||
entry.rgb[1] * (1 - ratio) + nextEntry.rgb[1] * ratio,
|
entry.rgb[1] * (1 - ratio) + nextEntry.rgb[1] * ratio,
|
||||||
entry.rgb[2] * (1 - ratio) + nextEntry.rgb[2] * ratio
|
entry.rgb[2] * (1 - ratio) + nextEntry.rgb[2] * ratio,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,7 +42,7 @@ const makePalette = (regl, entries) => {
|
|||||||
|
|
||||||
return make1DTexture(
|
return make1DTexture(
|
||||||
regl,
|
regl,
|
||||||
paletteColors.flat().map(i => i * 0xff)
|
paletteColors.flat().map((i) => i * 0xff)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -64,20 +62,18 @@ export default (regl, config, inputs) => {
|
|||||||
frag: regl.prop("frag"),
|
frag: regl.prop("frag"),
|
||||||
|
|
||||||
uniforms: {
|
uniforms: {
|
||||||
...extractEntries(config, [
|
...extractEntries(config, ["backgroundColor"]),
|
||||||
"backgroundColor",
|
|
||||||
]),
|
|
||||||
tex: inputs.primary,
|
tex: inputs.primary,
|
||||||
bloomTex: inputs.bloom,
|
bloomTex: inputs.bloom,
|
||||||
palette,
|
palette,
|
||||||
ditherMagnitude: 0.05
|
ditherMagnitude: 0.05,
|
||||||
},
|
},
|
||||||
framebuffer: output
|
framebuffer: output,
|
||||||
});
|
});
|
||||||
|
|
||||||
return makePass(
|
return makePass(
|
||||||
{
|
{
|
||||||
primary: output
|
primary: output,
|
||||||
},
|
},
|
||||||
() => render({ frag: palettePassFrag.text() }),
|
() => render({ frag: palettePassFrag.text() }),
|
||||||
null,
|
null,
|
||||||
|
|||||||
@@ -1,26 +1,18 @@
|
|||||||
import {
|
import { extractEntries, loadImage, loadText, makePassFBO, makeDoubleBuffer, makePass } from "./utils.js";
|
||||||
extractEntries,
|
|
||||||
loadImage,
|
|
||||||
loadText,
|
|
||||||
makePassFBO,
|
|
||||||
makeDoubleBuffer,
|
|
||||||
makePass
|
|
||||||
} from "./utils.js";
|
|
||||||
|
|
||||||
const rippleTypes = {
|
const rippleTypes = {
|
||||||
box: 0,
|
box: 0,
|
||||||
circle: 1
|
circle: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
const cycleStyles = {
|
const cycleStyles = {
|
||||||
cycleFasterWhenDimmed: 0,
|
cycleFasterWhenDimmed: 0,
|
||||||
cycleRandomly: 1
|
cycleRandomly: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
const numVerticesPerQuad = 2 * 3;
|
const numVerticesPerQuad = 2 * 3;
|
||||||
|
|
||||||
export default (regl, config) => {
|
export default (regl, config) => {
|
||||||
|
|
||||||
const volumetric = config.volumetric;
|
const volumetric = config.volumetric;
|
||||||
const density = volumetric && config.effect !== "none" ? config.density : 1;
|
const density = volumetric && config.effect !== "none" ? config.density : 1;
|
||||||
const [numRows, numColumns] = [config.numColumns, config.numColumns * density];
|
const [numRows, numColumns] = [config.numColumns, config.numColumns * density];
|
||||||
@@ -39,10 +31,9 @@ export default (regl, config) => {
|
|||||||
width: numColumns,
|
width: numColumns,
|
||||||
height: numRows,
|
height: numRows,
|
||||||
wrapT: "clamp",
|
wrapT: "clamp",
|
||||||
type: "half float"
|
type: "half float",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const output = makePassFBO(regl, config.useHalfFloat);
|
const output = makePassFBO(regl, config.useHalfFloat);
|
||||||
|
|
||||||
const uniforms = {
|
const uniforms = {
|
||||||
@@ -79,20 +70,13 @@ export default (regl, config) => {
|
|||||||
numQuadRows,
|
numQuadRows,
|
||||||
numQuadColumns,
|
numQuadColumns,
|
||||||
quadSize,
|
quadSize,
|
||||||
volumetric
|
volumetric,
|
||||||
};
|
};
|
||||||
|
|
||||||
uniforms.rippleType =
|
uniforms.rippleType = config.rippleTypeName in rippleTypes ? rippleTypes[config.rippleTypeName] : -1;
|
||||||
config.rippleTypeName in rippleTypes
|
uniforms.cycleStyle = config.cycleStyleName in cycleStyles ? cycleStyles[config.cycleStyleName] : 0;
|
||||||
? rippleTypes[config.rippleTypeName]
|
|
||||||
: -1;
|
|
||||||
uniforms.cycleStyle =
|
|
||||||
config.cycleStyleName in cycleStyles
|
|
||||||
? cycleStyles[config.cycleStyleName]
|
|
||||||
: 0;
|
|
||||||
uniforms.slantVec = [Math.cos(config.slant), Math.sin(config.slant)];
|
uniforms.slantVec = [Math.cos(config.slant), Math.sin(config.slant)];
|
||||||
uniforms.slantScale =
|
uniforms.slantScale = 1 / (Math.abs(Math.sin(2 * config.slant)) * (Math.sqrt(2) - 1) + 1);
|
||||||
1 / (Math.abs(Math.sin(2 * config.slant)) * (Math.sqrt(2) - 1) + 1);
|
|
||||||
uniforms.showComputationTexture = config.effect === "none";
|
uniforms.showComputationTexture = config.effect === "none";
|
||||||
|
|
||||||
const msdf = loadImage(regl, config.glyphTexURL);
|
const msdf = loadImage(regl, config.glyphTexURL);
|
||||||
@@ -102,19 +86,28 @@ export default (regl, config) => {
|
|||||||
frag: regl.prop("frag"),
|
frag: regl.prop("frag"),
|
||||||
uniforms: {
|
uniforms: {
|
||||||
...uniforms,
|
...uniforms,
|
||||||
lastState: doubleBuffer.back
|
lastState: doubleBuffer.back,
|
||||||
},
|
},
|
||||||
|
|
||||||
framebuffer: doubleBuffer.front
|
framebuffer: doubleBuffer.front,
|
||||||
});
|
});
|
||||||
|
|
||||||
const quadPositions = Array(numQuadRows).fill().map((_, y) =>
|
const quadPositions = Array(numQuadRows)
|
||||||
Array(numQuadColumns).fill().map((_, x) =>
|
.fill()
|
||||||
Array(numVerticesPerQuad).fill([x, y])
|
.map((_, y) =>
|
||||||
)
|
Array(numQuadColumns)
|
||||||
|
.fill()
|
||||||
|
.map((_, x) => Array(numVerticesPerQuad).fill([x, y]))
|
||||||
);
|
);
|
||||||
|
|
||||||
const quadCorners = Array(numQuads).fill([[0, 0], [0, 1], [1, 1], [0, 0], [1, 1], [1, 0]]);
|
const quadCorners = Array(numQuads).fill([
|
||||||
|
[0, 0],
|
||||||
|
[0, 1],
|
||||||
|
[1, 1],
|
||||||
|
[0, 0],
|
||||||
|
[1, 1],
|
||||||
|
[1, 0],
|
||||||
|
]);
|
||||||
|
|
||||||
// We render the code into an FBO using MSDFs: https://github.com/Chlumsky/msdfgen
|
// We render the code into an FBO using MSDFs: https://github.com/Chlumsky/msdfgen
|
||||||
const renderVert = loadText("../shaders/render.vert");
|
const renderVert = loadText("../shaders/render.vert");
|
||||||
@@ -126,8 +119,8 @@ export default (regl, config) => {
|
|||||||
srcRGB: "src alpha",
|
srcRGB: "src alpha",
|
||||||
srcAlpha: 1,
|
srcAlpha: 1,
|
||||||
dstRGB: "dst alpha",
|
dstRGB: "dst alpha",
|
||||||
dstAlpha: 1
|
dstAlpha: 1,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
vert: regl.prop("vert"),
|
vert: regl.prop("vert"),
|
||||||
frag: regl.prop("frag"),
|
frag: regl.prop("frag"),
|
||||||
@@ -140,16 +133,16 @@ export default (regl, config) => {
|
|||||||
|
|
||||||
camera: regl.prop("camera"),
|
camera: regl.prop("camera"),
|
||||||
transform: regl.prop("transform"),
|
transform: regl.prop("transform"),
|
||||||
screenSize: regl.prop("screenSize")
|
screenSize: regl.prop("screenSize"),
|
||||||
},
|
},
|
||||||
|
|
||||||
attributes: {
|
attributes: {
|
||||||
aPosition: quadPositions,
|
aPosition: quadPositions,
|
||||||
aCorner: quadCorners
|
aCorner: quadCorners,
|
||||||
},
|
},
|
||||||
count: numQuads * numVerticesPerQuad,
|
count: numQuads * numVerticesPerQuad,
|
||||||
|
|
||||||
framebuffer: output
|
framebuffer: output,
|
||||||
});
|
});
|
||||||
|
|
||||||
const screenSize = [1, 1];
|
const screenSize = [1, 1];
|
||||||
@@ -163,7 +156,7 @@ export default (regl, config) => {
|
|||||||
|
|
||||||
return makePass(
|
return makePass(
|
||||||
{
|
{
|
||||||
primary: output
|
primary: output,
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
const time = Date.now();
|
const time = Date.now();
|
||||||
@@ -172,7 +165,7 @@ export default (regl, config) => {
|
|||||||
regl.clear({
|
regl.clear({
|
||||||
depth: 1,
|
depth: 1,
|
||||||
color: [0, 0, 0, 1],
|
color: [0, 0, 0, 1],
|
||||||
framebuffer: output
|
framebuffer: output,
|
||||||
});
|
});
|
||||||
render({ camera, transform, screenSize, vert: renderVert.text(), frag: renderFrag.text() });
|
render({ camera, transform, screenSize, vert: renderVert.text(), frag: renderFrag.text() });
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -18,19 +18,17 @@ export default (regl, config, inputs) => {
|
|||||||
frag: regl.prop("frag"),
|
frag: regl.prop("frag"),
|
||||||
|
|
||||||
uniforms: {
|
uniforms: {
|
||||||
...extractEntries(config, [
|
...extractEntries(config, ["backgroundColor"]),
|
||||||
"backgroundColor",
|
|
||||||
]),
|
|
||||||
tex: inputs.primary,
|
tex: inputs.primary,
|
||||||
bloomTex: inputs.bloom,
|
bloomTex: inputs.bloom,
|
||||||
ditherMagnitude: 0.05
|
ditherMagnitude: 0.05,
|
||||||
},
|
},
|
||||||
framebuffer: output
|
framebuffer: output,
|
||||||
});
|
});
|
||||||
|
|
||||||
return makePass(
|
return makePass(
|
||||||
{
|
{
|
||||||
primary: output
|
primary: output,
|
||||||
},
|
},
|
||||||
() => render({ frag: resurrectionPassFrag.text() })
|
() => render({ frag: resurrectionPassFrag.text() })
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const neapolitanStripeColors = [
|
|||||||
[0.8, 0.8, 0.6],
|
[0.8, 0.8, 0.6],
|
||||||
[0.8, 0.8, 0.6],
|
[0.8, 0.8, 0.6],
|
||||||
[1.0, 0.7, 0.8],
|
[1.0, 0.7, 0.8],
|
||||||
[1.0, 0.7, 0.8]
|
[1.0, 0.7, 0.8],
|
||||||
].flat();
|
].flat();
|
||||||
|
|
||||||
const prideStripeColors = [
|
const prideStripeColors = [
|
||||||
@@ -15,22 +15,18 @@ const prideStripeColors = [
|
|||||||
[1, 1, 0],
|
[1, 1, 0],
|
||||||
[0, 1, 0],
|
[0, 1, 0],
|
||||||
[0, 0, 1],
|
[0, 0, 1],
|
||||||
[0.8, 0, 1]
|
[0.8, 0, 1],
|
||||||
].flat();
|
].flat();
|
||||||
|
|
||||||
export default (regl, config, inputs) => {
|
export default (regl, config, inputs) => {
|
||||||
const output = makePassFBO(regl, config.useHalfFloat);
|
const output = makePassFBO(regl, config.useHalfFloat);
|
||||||
|
|
||||||
const stripeColors =
|
const stripeColors =
|
||||||
"stripeColors" in config
|
"stripeColors" in config ? config.stripeColors.split(",").map(parseFloat) : config.effect === "pride" ? prideStripeColors : neapolitanStripeColors;
|
||||||
? config.stripeColors.split(",").map(parseFloat)
|
|
||||||
: config.effect === "pride"
|
|
||||||
? prideStripeColors
|
|
||||||
: neapolitanStripeColors;
|
|
||||||
const numStripeColors = Math.floor(stripeColors.length / 3);
|
const numStripeColors = Math.floor(stripeColors.length / 3);
|
||||||
const stripes = make1DTexture(
|
const stripes = make1DTexture(
|
||||||
regl,
|
regl,
|
||||||
stripeColors.slice(0, numStripeColors * 3).map(f => Math.floor(f * 0xff))
|
stripeColors.slice(0, numStripeColors * 3).map((f) => Math.floor(f * 0xff))
|
||||||
);
|
);
|
||||||
|
|
||||||
const stripePassFrag = loadText("../shaders/stripePass.frag");
|
const stripePassFrag = loadText("../shaders/stripePass.frag");
|
||||||
@@ -39,20 +35,18 @@ export default (regl, config, inputs) => {
|
|||||||
frag: regl.prop("frag"),
|
frag: regl.prop("frag"),
|
||||||
|
|
||||||
uniforms: {
|
uniforms: {
|
||||||
...extractEntries(config, [
|
...extractEntries(config, ["backgroundColor"]),
|
||||||
"backgroundColor",
|
|
||||||
]),
|
|
||||||
tex: inputs.primary,
|
tex: inputs.primary,
|
||||||
bloomTex: inputs.bloom,
|
bloomTex: inputs.bloom,
|
||||||
stripes,
|
stripes,
|
||||||
ditherMagnitude: 0.05
|
ditherMagnitude: 0.05,
|
||||||
},
|
},
|
||||||
framebuffer: output
|
framebuffer: output,
|
||||||
});
|
});
|
||||||
|
|
||||||
return makePass(
|
return makePass(
|
||||||
{
|
{
|
||||||
primary: output
|
primary: output,
|
||||||
},
|
},
|
||||||
() => render({ frag: stripePassFrag.text() }),
|
() => render({ frag: stripePassFrag.text() }),
|
||||||
null,
|
null,
|
||||||
|
|||||||
54
js/utils.js
54
js/utils.js
@@ -1,7 +1,4 @@
|
|||||||
const extractEntries = (src, keys) =>
|
const extractEntries = (src, keys) => Object.fromEntries(Array.from(Object.entries(src)).filter(([key]) => keys.includes(key)));
|
||||||
Object.fromEntries(
|
|
||||||
Array.from(Object.entries(src)).filter(([key]) => keys.includes(key))
|
|
||||||
);
|
|
||||||
|
|
||||||
const makePassTexture = (regl, halfFloat) =>
|
const makePassTexture = (regl, halfFloat) =>
|
||||||
regl.texture({
|
regl.texture({
|
||||||
@@ -10,7 +7,7 @@ const makePassTexture = (regl, halfFloat) =>
|
|||||||
type: halfFloat ? "half float" : "uint8",
|
type: halfFloat ? "half float" : "uint8",
|
||||||
wrap: "clamp",
|
wrap: "clamp",
|
||||||
min: "linear",
|
min: "linear",
|
||||||
mag: "linear"
|
mag: "linear",
|
||||||
});
|
});
|
||||||
|
|
||||||
const makePassFBO = (regl, halfFloat) => regl.framebuffer({ color: makePassTexture(regl, halfFloat) });
|
const makePassFBO = (regl, halfFloat) => regl.framebuffer({ color: makePassTexture(regl, halfFloat) });
|
||||||
@@ -20,7 +17,7 @@ const makePassFBO = (regl, halfFloat) => regl.framebuffer({ color: makePassTextu
|
|||||||
const makePyramid = (regl, height, halfFloat) =>
|
const makePyramid = (regl, height, halfFloat) =>
|
||||||
Array(height)
|
Array(height)
|
||||||
.fill()
|
.fill()
|
||||||
.map(_ => makePassFBO(regl, halfFloat));
|
.map((_) => makePassFBO(regl, halfFloat));
|
||||||
|
|
||||||
const makeDoubleBuffer = (regl, props) => {
|
const makeDoubleBuffer = (regl, props) => {
|
||||||
const state = Array(2)
|
const state = Array(2)
|
||||||
@@ -28,22 +25,17 @@ const makeDoubleBuffer = (regl, props) => {
|
|||||||
.map(() =>
|
.map(() =>
|
||||||
regl.framebuffer({
|
regl.framebuffer({
|
||||||
color: regl.texture(props),
|
color: regl.texture(props),
|
||||||
depthStencil: false
|
depthStencil: false,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
front: ({ tick }) => state[tick % 2],
|
front: ({ tick }) => state[tick % 2],
|
||||||
back: ({ tick }) => state[(tick + 1) % 2]
|
back: ({ tick }) => state[(tick + 1) % 2],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const resizePyramid = (pyramid, vw, vh, scale) =>
|
const resizePyramid = (pyramid, vw, vh, scale) =>
|
||||||
pyramid.forEach((fbo, index) =>
|
pyramid.forEach((fbo, index) => fbo.resize(Math.floor((vw * scale) / 2 ** index), Math.floor((vh * scale) / 2 ** index)));
|
||||||
fbo.resize(
|
|
||||||
Math.floor((vw * scale) / 2 ** index),
|
|
||||||
Math.floor((vh * scale) / 2 ** index)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const loadImage = (regl, url) => {
|
const loadImage = (regl, url) => {
|
||||||
let texture = regl.texture([[0]]);
|
let texture = regl.texture([[0]]);
|
||||||
@@ -66,10 +58,10 @@ const loadImage = (regl, url) => {
|
|||||||
data,
|
data,
|
||||||
mag: "linear",
|
mag: "linear",
|
||||||
min: "linear",
|
min: "linear",
|
||||||
flipY: true
|
flipY: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})()
|
})(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -94,10 +86,10 @@ const loadShader = (regl, url) => {
|
|||||||
data,
|
data,
|
||||||
mag: "linear",
|
mag: "linear",
|
||||||
min: "linear",
|
min: "linear",
|
||||||
flipY: true
|
flipY: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})()
|
})(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -116,7 +108,7 @@ const loadText = (url) => {
|
|||||||
text = await (await fetch(url)).text();
|
text = await (await fetch(url)).text();
|
||||||
loaded = true;
|
loaded = true;
|
||||||
}
|
}
|
||||||
})()
|
})(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -142,19 +134,18 @@ const makeFullScreenQuad = (regl, uniforms = {}, context = {}) =>
|
|||||||
`,
|
`,
|
||||||
|
|
||||||
attributes: {
|
attributes: {
|
||||||
aPosition: [-4, -4, 4, -4, 0, 4]
|
aPosition: [-4, -4, 4, -4, 0, 4],
|
||||||
},
|
},
|
||||||
count: 3,
|
count: 3,
|
||||||
|
|
||||||
uniforms: {
|
uniforms: {
|
||||||
...uniforms,
|
...uniforms,
|
||||||
time: regl.context("time")
|
time: regl.context("time"),
|
||||||
},
|
},
|
||||||
|
|
||||||
context,
|
context,
|
||||||
|
|
||||||
depth: { enable: false },
|
depth: { enable: false },
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const make1DTexture = (regl, data) =>
|
const make1DTexture = (regl, data) =>
|
||||||
@@ -164,7 +155,7 @@ const make1DTexture = (regl, data) =>
|
|||||||
height: 1,
|
height: 1,
|
||||||
format: "rgb",
|
format: "rgb",
|
||||||
mag: "linear",
|
mag: "linear",
|
||||||
min: "linear"
|
min: "linear",
|
||||||
});
|
});
|
||||||
|
|
||||||
const makePass = (outputs, render, resize, ready) => {
|
const makePass = (outputs, render, resize, ready) => {
|
||||||
@@ -172,8 +163,7 @@ const makePass = (outputs, render, resize, ready) => {
|
|||||||
render = () => {};
|
render = () => {};
|
||||||
}
|
}
|
||||||
if (resize == null) {
|
if (resize == null) {
|
||||||
resize = (w, h) =>
|
resize = (w, h) => Object.values(outputs).forEach((output) => output.resize(w, h));
|
||||||
Object.values(outputs).forEach(output => output.resize(w, h));
|
|
||||||
}
|
}
|
||||||
if (ready == null) {
|
if (ready == null) {
|
||||||
ready = Promise.resolve();
|
ready = Promise.resolve();
|
||||||
@@ -184,20 +174,12 @@ const makePass = (outputs, render, resize, ready) => {
|
|||||||
outputs,
|
outputs,
|
||||||
render,
|
render,
|
||||||
resize,
|
resize,
|
||||||
ready
|
ready,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const makePipeline = (steps, getInputs, ...params) =>
|
const makePipeline = (steps, getInputs, ...params) =>
|
||||||
steps
|
steps.filter((f) => f != null).reduce((pipeline, f, i) => [...pipeline, f(...params, i == 0 ? null : getInputs(pipeline[i - 1]))], []);
|
||||||
.filter(f => f != null)
|
|
||||||
.reduce(
|
|
||||||
(pipeline, f, i) => [
|
|
||||||
...pipeline,
|
|
||||||
f(...params, i == 0 ? null : getInputs(pipeline[i - 1]))
|
|
||||||
],
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
extractEntries,
|
extractEntries,
|
||||||
@@ -211,5 +193,5 @@ export {
|
|||||||
makeFullScreenQuad,
|
makeFullScreenQuad,
|
||||||
make1DTexture,
|
make1DTexture,
|
||||||
makePass,
|
makePass,
|
||||||
makePipeline
|
makePipeline,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user