mirror of
https://github.com/Rezmason/matrix.git
synced 2026-04-14 12:29:30 -07:00
Added cache check to WebGPU renderer's loadShader method. Un-commented entries into config.js. Inclusions are now explicit dynamic import lambdas, so the cache functions can detect and call them; however, webpack and rollup seem to use them differently.
This commit is contained in:
16
TODO.txt
16
TODO.txt
@@ -1,4 +1,19 @@
|
||||
TODO:
|
||||
Make sure component works right
|
||||
bundled, of course
|
||||
webpack?
|
||||
Minimum react requirement?
|
||||
Move off of regl
|
||||
Unify implementations?
|
||||
Responsive changes
|
||||
Move start time to rain object
|
||||
Matrix component should record, then overwrite it
|
||||
Reshape all passes to react to config changes, ie. "configure"
|
||||
main.js "formulate" --> "configure"
|
||||
simple deltas only require updating the uniforms
|
||||
return boolean of whether all deltas are simple
|
||||
Resource changes are simple if they're cached and loaded, false otherwise
|
||||
remake the pipeline if anything returns false
|
||||
Create multiple distributions
|
||||
core
|
||||
One embedded MSDF, combined from the two main glyph sets and their configs
|
||||
@@ -7,7 +22,6 @@ TODO:
|
||||
and then one with built-in MSDF generation
|
||||
(TTF + glyphString) --> MSDF
|
||||
Is MSDF strictly necessary?
|
||||
Move off of regl
|
||||
Expanded configurability
|
||||
Modify regl pass
|
||||
async build(config, inputs)
|
||||
|
||||
11
js/Matrix.js
11
js/Matrix.js
@@ -112,7 +112,9 @@ export const Matrix = memo((props) => {
|
||||
const [rRenderer, setRenderer] = useState(null);
|
||||
const [rRain, setRain] = useState(null);
|
||||
|
||||
const configProps = Object.fromEntries(Object.entries(rawConfigProps).filter(([_, value]) => value != null));
|
||||
const configProps = Object.fromEntries(
|
||||
Object.entries(rawConfigProps).filter(([_, value]) => value != null),
|
||||
);
|
||||
|
||||
const supportsWebGPU = () => {
|
||||
return (
|
||||
@@ -155,7 +157,12 @@ export const Matrix = memo((props) => {
|
||||
setCanvas(canvas);
|
||||
|
||||
const loadRain = async () => {
|
||||
const renderer = await import(`./${useWebGPU ? "webgpu" : "regl"}/main.js`);
|
||||
let renderer;
|
||||
if (useWebGPU) {
|
||||
renderer = await import("./webgpu/main.js");
|
||||
} else {
|
||||
renderer = await import("./regl/main.js");
|
||||
}
|
||||
setRenderer(renderer);
|
||||
const rain = await renderer.init(canvas);
|
||||
setRain(rain);
|
||||
|
||||
@@ -2,7 +2,4 @@ import { Matrix } from "./Matrix";
|
||||
import inclusions from "./inclusions";
|
||||
import * as reglRenderer from "./regl/main";
|
||||
import * as webgpuRenderer from "./webgpu/main";
|
||||
globalThis.inclusions = inclusions;
|
||||
globalThis.reglRenderer = reglRenderer;
|
||||
globalThis.webgpuRenderer = webgpuRenderer;
|
||||
globalThis.Matrix = Matrix;
|
||||
export { inclusions, reglRenderer, webgpuRenderer, Matrix };
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
export default async () => {
|
||||
let glMatrix, createREGL;
|
||||
let glMatrix, createREGL, inclusions;
|
||||
|
||||
try {
|
||||
glMatrix = await import("gl-matrix");
|
||||
createREGL = (await import("regl")).default;
|
||||
inclusions = (await import("./inclusions.js")).default;
|
||||
} catch {
|
||||
const loadJS = (src) =>
|
||||
new Promise((resolve, reject) => {
|
||||
@@ -14,7 +15,8 @@ export default async () => {
|
||||
await Promise.all([loadJS("lib/regl.min.js"), loadJS("lib/gl-matrix.js")]);
|
||||
glMatrix = globalThis.glMatrix;
|
||||
createREGL = globalThis.createREGL;
|
||||
inclusions = [];
|
||||
}
|
||||
|
||||
return { glMatrix, createREGL };
|
||||
return { glMatrix, createREGL, inclusions };
|
||||
};
|
||||
|
||||
145
js/inclusions.js
145
js/inclusions.js
@@ -1,75 +1,74 @@
|
||||
import highPassFrag from "../shaders/glsl/bloomPass.highPass.frag.glsl";
|
||||
import blurFrag from "../shaders/glsl/bloomPass.blur.frag.glsl";
|
||||
import combineFrag from "../shaders/glsl/bloomPass.combine.frag.glsl";
|
||||
import imagePassFrag from "../shaders/glsl/imagePass.frag.glsl";
|
||||
import mirrorPassFrag from "../shaders/glsl/mirrorPass.frag.glsl";
|
||||
import palettePassFrag from "../shaders/glsl/palettePass.frag.glsl";
|
||||
import rainPassIntro from "../shaders/glsl/rainPass.intro.frag.glsl";
|
||||
import rainPassRaindrop from "../shaders/glsl/rainPass.raindrop.frag.glsl";
|
||||
import rainPassSymbol from "../shaders/glsl/rainPass.symbol.frag.glsl";
|
||||
import rainPassEffect from "../shaders/glsl/rainPass.effect.frag.glsl";
|
||||
import rainPassVert from "../shaders/glsl/rainPass.vert.glsl";
|
||||
import rainPassFrag from "../shaders/glsl/rainPass.frag.glsl";
|
||||
import stripePassFrag from "../shaders/glsl/stripePass.frag.glsl";
|
||||
import msdfCoptic from "../assets/coptic_msdf.png";
|
||||
import msdfGothic from "../assets/gothic_msdf.png";
|
||||
import msdfMatrixCode from "../assets/matrixcode_msdf.png";
|
||||
import msdfRes from "../assets/resurrections_msdf.png";
|
||||
// import megacity from "../assets/megacity_msdf.png";
|
||||
import msdfResGlint from "../assets/resurrections_glint_msdf.png";
|
||||
// import msdfHuberfishA from "../assets/huberfish_a_msdf.png";
|
||||
// import msdfHuberfishD from "../assets/huberfish_d_msdf.png";
|
||||
// import msdfGtargTenretni from "../assets/gtarg_tenretniolleh_msdf.png";
|
||||
// import msdfGtargAlienText from "../assets/gtarg_alientext_msdf.png";
|
||||
// import msdfNeoMatrixology from "../assets/neomatrixology_msdf.png";
|
||||
// import texSand from "../assets/sand.png";
|
||||
// import texPixels from "../assets/pixel_grid.png";
|
||||
import texMesh from "../assets/mesh.png";
|
||||
import texMetal from "../assets/metal.png";
|
||||
import bloomBlurShader from "../shaders/wgsl/bloomBlur.wgsl";
|
||||
import bloomCombineShader from "../shaders/wgsl/bloomCombine.wgsl";
|
||||
import endPassShader from "../shaders/wgsl/endPass.wgsl";
|
||||
import imagePassShader from "../shaders/wgsl/imagePass.wgsl";
|
||||
import mirrorPassShader from "../shaders/wgsl/mirrorPass.wgsl";
|
||||
import palettePassShader from "../shaders/wgsl/palettePass.wgsl";
|
||||
import rainPassShader from "../shaders/wgsl/rainPass.wgsl";
|
||||
import stripePassShader from "../shaders/wgsl/stripePass.wgsl";
|
||||
|
||||
export default [
|
||||
highPassFrag,
|
||||
blurFrag,
|
||||
combineFrag,
|
||||
imagePassFrag,
|
||||
mirrorPassFrag,
|
||||
palettePassFrag,
|
||||
rainPassIntro,
|
||||
rainPassRaindrop,
|
||||
rainPassSymbol,
|
||||
rainPassEffect,
|
||||
rainPassVert,
|
||||
rainPassFrag,
|
||||
stripePassFrag,
|
||||
msdfCoptic,
|
||||
msdfGothic,
|
||||
msdfMatrixCode,
|
||||
msdfRes,
|
||||
// megacity,
|
||||
msdfResGlint,
|
||||
// msdfHuberfishA,
|
||||
// msdfHuberfishD,
|
||||
// msdfGtargTenretni,
|
||||
// msdfGtargAlienText,
|
||||
// msdfNeoMatrixology,
|
||||
// texSand,
|
||||
// texPixels,
|
||||
texMesh,
|
||||
texMetal,
|
||||
bloomBlurShader,
|
||||
bloomCombineShader,
|
||||
endPassShader,
|
||||
imagePassShader,
|
||||
mirrorPassShader,
|
||||
palettePassShader,
|
||||
rainPassShader,
|
||||
stripePassShader,
|
||||
[
|
||||
"import::shaders/glsl/bloomPass.highPass.frag.glsl",
|
||||
() => import("../shaders/glsl/bloomPass.highPass.frag.glsl"),
|
||||
],
|
||||
[
|
||||
"import::shaders/glsl/bloomPass.blur.frag.glsl",
|
||||
() => import("../shaders/glsl/bloomPass.blur.frag.glsl"),
|
||||
],
|
||||
[
|
||||
"import::shaders/glsl/bloomPass.combine.frag.glsl",
|
||||
() => import("../shaders/glsl/bloomPass.combine.frag.glsl"),
|
||||
],
|
||||
["import::shaders/glsl/imagePass.frag.glsl", () => import("../shaders/glsl/imagePass.frag.glsl")],
|
||||
[
|
||||
"import::shaders/glsl/mirrorPass.frag.glsl",
|
||||
() => import("../shaders/glsl/mirrorPass.frag.glsl"),
|
||||
],
|
||||
[
|
||||
"import::shaders/glsl/palettePass.frag.glsl",
|
||||
() => import("../shaders/glsl/palettePass.frag.glsl"),
|
||||
],
|
||||
[
|
||||
"import::shaders/glsl/rainPass.intro.frag.glsl",
|
||||
() => import("../shaders/glsl/rainPass.intro.frag.glsl"),
|
||||
],
|
||||
[
|
||||
"import::shaders/glsl/rainPass.raindrop.frag.glsl",
|
||||
() => import("../shaders/glsl/rainPass.raindrop.frag.glsl"),
|
||||
],
|
||||
[
|
||||
"import::shaders/glsl/rainPass.symbol.frag.glsl",
|
||||
() => import("../shaders/glsl/rainPass.symbol.frag.glsl"),
|
||||
],
|
||||
[
|
||||
"import::shaders/glsl/rainPass.effect.frag.glsl",
|
||||
() => import("../shaders/glsl/rainPass.effect.frag.glsl"),
|
||||
],
|
||||
["import::shaders/glsl/rainPass.vert.glsl", () => import("../shaders/glsl/rainPass.vert.glsl")],
|
||||
["import::shaders/glsl/rainPass.frag.glsl", () => import("../shaders/glsl/rainPass.frag.glsl")],
|
||||
[
|
||||
"import::shaders/glsl/stripePass.frag.glsl",
|
||||
() => import("../shaders/glsl/stripePass.frag.glsl"),
|
||||
],
|
||||
["import::assets/coptic_msdf.png", () => import("../assets/coptic_msdf.png")],
|
||||
["import::assets/gothic_msdf.png", () => import("../assets/gothic_msdf.png")],
|
||||
["import::assets/matrixcode_msdf.png", () => import("../assets/matrixcode_msdf.png")],
|
||||
["import::assets/resurrections_msdf.png", () => import("../assets/resurrections_msdf.png")],
|
||||
["import::assets/megacity_msdf.png", () => import("../assets/megacity_msdf.png")],
|
||||
[
|
||||
"import::assets/resurrections_glint_msdf.png",
|
||||
() => import("../assets/resurrections_glint_msdf.png"),
|
||||
],
|
||||
["import::assets/huberfish_a_msdf.png", () => import("../assets/huberfish_a_msdf.png")],
|
||||
["import::assets/huberfish_d_msdf.png", () => import("../assets/huberfish_d_msdf.png")],
|
||||
[
|
||||
"import::assets/gtarg_tenretniolleh_msdf.png",
|
||||
() => import("../assets/gtarg_tenretniolleh_msdf.png"),
|
||||
],
|
||||
["import::assets/gtarg_alientext_msdf.png", () => import("../assets/gtarg_alientext_msdf.png")],
|
||||
["import::assets/neomatrixology_msdf.png", () => import("../assets/neomatrixology_msdf.png")],
|
||||
["import::assets/sand.png", () => import("../assets/sand.png")],
|
||||
["import::assets/pixel_grid.png", () => import("../assets/pixel_grid.png")],
|
||||
["import::assets/mesh.png", () => import("../assets/mesh.png")],
|
||||
["import::assets/metal.png", () => import("../assets/metal.png")],
|
||||
["import::shaders/wgsl/bloomBlur.wgsl", () => import("../shaders/wgsl/bloomBlur.wgsl")],
|
||||
["import::shaders/wgsl/bloomCombine.wgsl", () => import("../shaders/wgsl/bloomCombine.wgsl")],
|
||||
["import::shaders/wgsl/endPass.wgsl", () => import("../shaders/wgsl/endPass.wgsl")],
|
||||
["import::shaders/wgsl/imagePass.wgsl", () => import("../shaders/wgsl/imagePass.wgsl")],
|
||||
["import::shaders/wgsl/mirrorPass.wgsl", () => import("../shaders/wgsl/mirrorPass.wgsl")],
|
||||
["import::shaders/wgsl/palettePass.wgsl", () => import("../shaders/wgsl/palettePass.wgsl")],
|
||||
["import::shaders/wgsl/rainPass.wgsl", () => import("../shaders/wgsl/rainPass.wgsl")],
|
||||
["import::shaders/wgsl/stripePass.wgsl", () => import("../shaders/wgsl/stripePass.wgsl")],
|
||||
];
|
||||
|
||||
31
js/index.js
31
js/index.js
@@ -4,7 +4,6 @@ import { createRoot } from "react-dom/client";
|
||||
import { Matrix } from "./Matrix";
|
||||
|
||||
const root = createRoot(document.getElementById("root"));
|
||||
let idx = 1;
|
||||
const versions = [
|
||||
"classic",
|
||||
"3d",
|
||||
@@ -17,24 +16,42 @@ const versions = [
|
||||
"bugs",
|
||||
"morpheus",
|
||||
];
|
||||
const effects = ["none", "plain", "palette", "stripes", "pride", "trans", "image", "mirror"];
|
||||
const App = () => {
|
||||
const [version, setVersion] = useState(versions[0]);
|
||||
const [effect, setEffect] = useState("plain");
|
||||
const [numColumns, setNumColumns] = useState(80);
|
||||
const [cursorColor, setCursorColor] = useState(null);
|
||||
const [backgroundColor, setBackgroundColor] = useState("0,0,0");
|
||||
const [rendererType, setRendererType] = useState(null);
|
||||
const [density, setDensity] = useState(2);
|
||||
const [destroyed, setDestroyed] = useState(false);
|
||||
const onButtonClick = () => {
|
||||
const onVersionButtonClick = () => {
|
||||
setVersion((s) => {
|
||||
const newVersion = versions[idx];
|
||||
idx = (idx + 1) % versions.length;
|
||||
console.log(newVersion);
|
||||
let index = versions.indexOf(version) + 1;
|
||||
if (index === versions.length) {
|
||||
index = 0;
|
||||
}
|
||||
const newVersion = versions[index];
|
||||
console.log("version:", newVersion);
|
||||
return newVersion;
|
||||
});
|
||||
setCursorColor(null);
|
||||
setBackgroundColor(null);
|
||||
};
|
||||
const onEffectButtonClick = () => {
|
||||
setEffect((s) => {
|
||||
let index = effects.indexOf(effect) + 1;
|
||||
if (index === effects.length) {
|
||||
index = 0;
|
||||
}
|
||||
const newEffect = effects[index];
|
||||
console.log("effect:", newEffect);
|
||||
return newEffect;
|
||||
});
|
||||
setCursorColor(null);
|
||||
setBackgroundColor(null);
|
||||
};
|
||||
const onRendererButtonClick = () => {
|
||||
setRendererType(() => (rendererType === "webgpu" ? "regl" : "webgpu"));
|
||||
};
|
||||
@@ -45,7 +62,8 @@ const App = () => {
|
||||
return (
|
||||
<div>
|
||||
<h1>Rain</h1>
|
||||
<button onClick={onButtonClick}>Version: "{version}"</button>
|
||||
<button onClick={onVersionButtonClick}>Version: "{version}"</button>
|
||||
<button onClick={onEffectButtonClick}>Effect: "{effect}"</button>
|
||||
<button onClick={onRendererButtonClick}>Renderer: {rendererType ?? "default (regl)"}</button>
|
||||
<button onClick={onDestroyButtonClick}>Destroy</button>
|
||||
<label htmlFor="cursor-color">Cursor color: </label>
|
||||
@@ -86,6 +104,7 @@ const App = () => {
|
||||
<Matrix
|
||||
style={{ width: "80vw", height: "45vh" }}
|
||||
version={version}
|
||||
effect={effect}
|
||||
numColumns={numColumns}
|
||||
renderer={rendererType}
|
||||
cursorColor={cursorColor}
|
||||
|
||||
@@ -21,12 +21,13 @@ const effects = {
|
||||
mirror: makeMirrorPass,
|
||||
};
|
||||
|
||||
let createREGL, glMatrix;
|
||||
let createREGL, glMatrix, inclusions;
|
||||
|
||||
export const init = async (canvas) => {
|
||||
const libraries = await fetchLibraries();
|
||||
createREGL = libraries.createREGL;
|
||||
glMatrix = libraries.glMatrix;
|
||||
inclusions = libraries.inclusions;
|
||||
|
||||
const resize = () => {
|
||||
const devicePixelRatio = window.devicePixelRatio ?? 1;
|
||||
|
||||
@@ -17,14 +17,12 @@ const fonts = {
|
||||
glyphSequenceLength: 57,
|
||||
glyphTextureGridSize: [8, 8],
|
||||
},
|
||||
/*
|
||||
megacity: {
|
||||
// The glyphs seen in the film trilogy
|
||||
glyphMSDFURL: "assets/megacity_msdf.png",
|
||||
glyphSequenceLength: 64,
|
||||
glyphTextureGridSize: [8, 8],
|
||||
},
|
||||
*/
|
||||
resurrections: {
|
||||
// The glyphs seen in the film trilogy
|
||||
glyphMSDFURL: "assets/resurrections_msdf.png",
|
||||
@@ -32,7 +30,6 @@ const fonts = {
|
||||
glyphSequenceLength: 135,
|
||||
glyphTextureGridSize: [13, 12],
|
||||
},
|
||||
/*
|
||||
huberfishA: {
|
||||
glyphMSDFURL: "assets/huberfish_a_msdf.png",
|
||||
glyphSequenceLength: 34,
|
||||
@@ -58,12 +55,11 @@ const fonts = {
|
||||
glyphSequenceLength: 12,
|
||||
glyphTextureGridSize: [4, 4],
|
||||
},
|
||||
*/
|
||||
};
|
||||
|
||||
const textureURLs = {
|
||||
// sand: "assets/sand.png",
|
||||
// pixels: "assets/pixel_grid.png",
|
||||
sand: "assets/sand.png",
|
||||
pixels: "assets/pixel_grid.png",
|
||||
mesh: "assets/mesh.png",
|
||||
metal: "assets/metal.png",
|
||||
};
|
||||
@@ -136,7 +132,6 @@ const defaults = {
|
||||
|
||||
const versions = {
|
||||
classic: {},
|
||||
/*
|
||||
megacity: {
|
||||
font: "megacity",
|
||||
animationSpeed: 0.5,
|
||||
@@ -155,7 +150,6 @@ const versions = {
|
||||
cursorColor: hsl(0.167, 1, 0.75),
|
||||
cursorIntensity: 2,
|
||||
},
|
||||
*/
|
||||
operator: {
|
||||
cursorColor: hsl(0.375, 1, 0.66),
|
||||
cursorIntensity: 3,
|
||||
@@ -268,7 +262,6 @@ const versions = {
|
||||
raindropLength: 0.3,
|
||||
density: 0.75,
|
||||
},
|
||||
/*
|
||||
morpheus: {
|
||||
font: "resurrections",
|
||||
glintTexture: "mesh",
|
||||
@@ -358,7 +351,6 @@ const versions = {
|
||||
// { color: hsl(0.1, 1.0, 0.9), at: 1.0 },
|
||||
],
|
||||
},
|
||||
*/
|
||||
["3d"]: {
|
||||
volumetric: true,
|
||||
fallSpeed: 0.5,
|
||||
|
||||
@@ -39,7 +39,7 @@ const makePyramidViews = (pyramid) => pyramid.map((tex) => tex.createView());
|
||||
// The bloom pass is basically an added blur of the rain pass's high-pass output.
|
||||
// The blur approximation is the sum of a pyramid of downscaled, blurred textures.
|
||||
|
||||
export default ({ config, device }) => {
|
||||
export default ({ config, device, cache }) => {
|
||||
const pyramidHeight = 4;
|
||||
const bloomSize = config.bloomSize;
|
||||
const bloomStrength = config.bloomStrength;
|
||||
@@ -54,8 +54,8 @@ export default ({ config, device }) => {
|
||||
}
|
||||
|
||||
const assets = [
|
||||
loadShader(device, "shaders/wgsl/bloomBlur.wgsl"),
|
||||
loadShader(device, "shaders/wgsl/bloomCombine.wgsl"),
|
||||
loadShader(device, cache, "shaders/wgsl/bloomBlur.wgsl"),
|
||||
loadShader(device, cache, "shaders/wgsl/bloomCombine.wgsl"),
|
||||
];
|
||||
|
||||
const linearSampler = device.createSampler({
|
||||
|
||||
@@ -5,7 +5,7 @@ import { loadShader, makeBindGroup, makePass } from "./utils.js";
|
||||
|
||||
const numVerticesPerQuad = 2 * 3;
|
||||
|
||||
export default ({ device, canvasFormat, canvasContext }) => {
|
||||
export default ({ device, cache, canvasFormat, canvasContext }) => {
|
||||
const nearestSampler = device.createSampler();
|
||||
|
||||
const renderPassConfig = {
|
||||
@@ -21,7 +21,7 @@ export default ({ device, canvasFormat, canvasContext }) => {
|
||||
let renderPipeline;
|
||||
let renderBindGroup;
|
||||
|
||||
const assets = [loadShader(device, "shaders/wgsl/endPass.wgsl")];
|
||||
const assets = [loadShader(device, cache, "shaders/wgsl/endPass.wgsl")];
|
||||
|
||||
const loaded = (async () => {
|
||||
const [imageShader] = await Promise.all(assets);
|
||||
|
||||
@@ -17,7 +17,7 @@ export default ({ config, cache, device }) => {
|
||||
const bgURL = "bgURL" in config ? config.bgURL : defaultBGURL;
|
||||
const assets = [
|
||||
loadTexture(device, cache, bgURL),
|
||||
loadShader(device, "shaders/wgsl/imagePass.wgsl"),
|
||||
loadShader(device, cache, "shaders/wgsl/imagePass.wgsl"),
|
||||
];
|
||||
|
||||
const linearSampler = device.createSampler({
|
||||
|
||||
@@ -24,11 +24,12 @@ const effects = {
|
||||
mirror: makeMirrorPass,
|
||||
};
|
||||
|
||||
let glMatrix;
|
||||
let glMatrix, inclusions;
|
||||
|
||||
export const init = async (canvas) => {
|
||||
const libraries = await fetchLibraries();
|
||||
glMatrix = libraries.glMatrix;
|
||||
inclusions = libraries.inclusions;
|
||||
|
||||
const resize = () => {
|
||||
const devicePixelRatio = window.devicePixelRatio ?? 1;
|
||||
|
||||
@@ -24,8 +24,8 @@ window.onclick = (e) => {
|
||||
touchesChanged = true;
|
||||
};
|
||||
|
||||
export default ({ config, device, cameraTex, cameraAspectRatio, timeBuffer }) => {
|
||||
const assets = [loadShader(device, "shaders/wgsl/mirrorPass.wgsl")];
|
||||
export default ({ config, device, cache, cameraTex, cameraAspectRatio, timeBuffer }) => {
|
||||
const assets = [loadShader(device, cache, "shaders/wgsl/mirrorPass.wgsl")];
|
||||
|
||||
const linearSampler = device.createSampler({
|
||||
magFilter: "linear",
|
||||
|
||||
@@ -73,7 +73,7 @@ const makePalette = (device, paletteUniforms, entries) => {
|
||||
// won't persist across subsequent frames. This is a safe trick
|
||||
// in screen space.
|
||||
|
||||
export default ({ config, device, timeBuffer }) => {
|
||||
export default ({ config, device, cache, timeBuffer }) => {
|
||||
const linearSampler = device.createSampler({
|
||||
magFilter: "linear",
|
||||
minFilter: "linear",
|
||||
@@ -86,7 +86,7 @@ export default ({ config, device, timeBuffer }) => {
|
||||
let output;
|
||||
let screenSize;
|
||||
|
||||
const assets = [loadShader(device, "shaders/wgsl/palettePass.wgsl")];
|
||||
const assets = [loadShader(device, cache, "shaders/wgsl/palettePass.wgsl")];
|
||||
|
||||
const loaded = (async () => {
|
||||
const [paletteShader] = await Promise.all(assets);
|
||||
|
||||
@@ -39,7 +39,7 @@ export default ({ config, glMatrix, cache, device, timeBuffer }) => {
|
||||
loadTexture(device, cache, config.glintMSDFURL),
|
||||
loadTexture(device, cache, config.baseTextureURL, false, true),
|
||||
loadTexture(device, cache, config.glintTextureURL, false, true),
|
||||
loadShader(device, "shaders/wgsl/rainPass.wgsl"),
|
||||
loadShader(device, cache, "shaders/wgsl/rainPass.wgsl"),
|
||||
];
|
||||
|
||||
// The volumetric mode multiplies the number of columns
|
||||
|
||||
@@ -43,7 +43,7 @@ const numVerticesPerQuad = 2 * 3;
|
||||
// won't persist across subsequent frames. This is a safe trick
|
||||
// in screen space.
|
||||
|
||||
export default ({ config, device, timeBuffer }) => {
|
||||
export default ({ config, device, cache, timeBuffer }) => {
|
||||
// Expand and convert stripe colors into 1D texture data
|
||||
const stripeColors =
|
||||
"stripeColors" in config
|
||||
@@ -68,7 +68,7 @@ export default ({ config, device, timeBuffer }) => {
|
||||
let output;
|
||||
let screenSize;
|
||||
|
||||
const assets = [loadShader(device, "shaders/wgsl/stripePass.wgsl")];
|
||||
const assets = [loadShader(device, cache, "shaders/wgsl/stripePass.wgsl")];
|
||||
|
||||
const loaded = (async () => {
|
||||
const [stripeShader] = await Promise.all(assets);
|
||||
|
||||
@@ -62,7 +62,11 @@ const makeComputeTarget = (device, size, mipLevelCount = 1) =>
|
||||
GPUTextureUsage.STORAGE_BINDING,
|
||||
});
|
||||
|
||||
const loadShader = async (device, url) => {
|
||||
const loadShader = async (device, cache, url) => {
|
||||
const key = url;
|
||||
if (cache.has(key)) {
|
||||
return cache.get(key);
|
||||
}
|
||||
const response = await fetch(url);
|
||||
const code = await response.text();
|
||||
return {
|
||||
|
||||
60
package.json
60
package.json
@@ -1,10 +1,21 @@
|
||||
{
|
||||
"name": "react-matrix-rain",
|
||||
"version": "1.0.0",
|
||||
"description": "web-based green code rain, made with love, for react",
|
||||
"main": "dist/index.cjs.js",
|
||||
"name": "digital-rain",
|
||||
"version": "0.1.0",
|
||||
"description": "web-based green code rain, made with love",
|
||||
"type": "module",
|
||||
"main": "./dist/digital-rain.cjs",
|
||||
"module": "./dist/digital-rain.module.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/digital-rain.module.js",
|
||||
"require": "./dist/digital-rain.cjs"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"/dist"
|
||||
"/dist",
|
||||
"LICENSE",
|
||||
"package.json",
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
@@ -12,12 +23,35 @@
|
||||
"start": "npm run format ; webpack serve --config ./webpack.config.js",
|
||||
"build": "npm run format ; rollup -c"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"keywords": [
|
||||
"rain",
|
||||
"matrix",
|
||||
"javascript",
|
||||
"webgl",
|
||||
"webgl-computer-graphics",
|
||||
"matrix-rain",
|
||||
"matrix-digital-rain"
|
||||
],
|
||||
"author": {
|
||||
"name": "Rezmason",
|
||||
"url": "https://rezmason.net"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "nohren"
|
||||
}
|
||||
],
|
||||
"homepage": "https://github.com/Rezmason/matrix",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Rezmason/matrix"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/Rezmason/matrix/issues"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"gl-matrix": "^3.4.3",
|
||||
"holoplay-core": "^0.0.9",
|
||||
"regl": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -46,5 +80,13 @@
|
||||
"peerDependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ import terser from "@rollup/plugin-terser";
|
||||
import { string } from "rollup-plugin-string";
|
||||
import image from "@rollup/plugin-image";
|
||||
|
||||
export default {
|
||||
export default [
|
||||
{
|
||||
input: "js/bundle-contents.js",
|
||||
external: ["react", "react-dom"], // keep them out of your bundle
|
||||
plugins: [
|
||||
@@ -34,14 +35,38 @@ export default {
|
||||
includeAssets: true,
|
||||
}), // bundle-size treemap
|
||||
],
|
||||
output: [
|
||||
{
|
||||
output: {
|
||||
inlineDynamicImports: true,
|
||||
file: "dist/index.cjs.js",
|
||||
file: "dist/digital-rain.cjs.js",
|
||||
format: "cjs",
|
||||
exports: "named",
|
||||
sourcemap: false,
|
||||
},
|
||||
// { file: 'dist/index.esm.js', format: 'es' } // optional ESM build
|
||||
},
|
||||
{
|
||||
input: "js/bundle-contents.js",
|
||||
external: ["react", "react-dom"], // keep them out of your bundle
|
||||
plugins: [
|
||||
peerDepsExternal(), // auto-exclude peerDeps
|
||||
nodeResolve(), // so Rollup can find deps in node_modules
|
||||
string({ include: ["**/*.glsl"] }),
|
||||
string({ include: ["**/*.wgsl"] }),
|
||||
image({ include: ["**/*.png"], limit: 0 }),
|
||||
babel({
|
||||
exclude: "node_modules/**", // transpile JSX
|
||||
babelHelpers: "bundled",
|
||||
presets: ["@babel/preset-react", "@babel/preset-env"],
|
||||
}),
|
||||
commonjs(), // turn CJS deps into ES
|
||||
],
|
||||
};
|
||||
output: [
|
||||
{
|
||||
inlineDynamicImports: true,
|
||||
file: "dist/digital-rain.module.js",
|
||||
format: "es",
|
||||
exports: "named",
|
||||
sourcemap: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
const webpack = require("webpack");
|
||||
const path = require("path");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
const CopyPlugin = require("copy-webpack-plugin");
|
||||
import webpack from "webpack";
|
||||
import path from "path";
|
||||
import HtmlWebpackPlugin from "html-webpack-plugin";
|
||||
import CopyPlugin from "copy-webpack-plugin";
|
||||
|
||||
module.exports = {
|
||||
import { dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
export default {
|
||||
mode: "development",
|
||||
entry: path.resolve(__dirname, "./js/index.js"),
|
||||
module: {
|
||||
|
||||
Reference in New Issue
Block a user