Skip to content
This repository was archived by the owner on Jun 19, 2025. It is now read-only.

Commit 2cf77b0

Browse files
Remove uniform pattern function and expose the shader instance
1 parent 65cc317 commit 2cf77b0

File tree

5 files changed

+81
-223
lines changed

5 files changed

+81
-223
lines changed

packages/shader/index.mjs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
export * from './shader.mjs';
2-
export * from './uniform.mjs';

packages/shader/shader.mjs

Lines changed: 81 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -34,88 +34,104 @@ void main(void) {
3434
`;
3535
}
3636

37-
// Modulation helpers to smooth the values.
37+
// Helper class to handle uniform updates
3838
class UniformValue {
39-
constructor() {
40-
this.value = 0;
41-
this.desired = 0;
42-
this.slow = 10;
39+
constructor(name, count, draw) {
40+
this.name = name;
41+
this.draw = draw;
42+
this.isArray = count > 0;
43+
this.value = new Array(Math.max(1, count)).fill(0);
44+
this.frameModifier = new Array(Math.max(1, count)).fill(null);
4345
}
4446

45-
get(elapsed) {
46-
// Adjust the value according to the rate of change
47-
const offset = (this.desired - this.value) / (this.slow * Math.max(1, elapsed * 60));
48-
// Ignore small changes
49-
if (Math.abs(offset) > 1e-3) this.value += offset;
50-
return this.value;
51-
}
52-
}
53-
54-
// Set an uniform value (from a pattern).
55-
export function setUniform(instanceName, name, value, incr, position, slow) {
56-
const instance = _instances[instanceName];
57-
if (!instance) {
58-
logger('[shader] not loaded yet', 'warning');
59-
return;
47+
incr(value, pos = 0) {
48+
const idx = pos % this.value.length;
49+
this.value[idx] += value;
50+
this.frameModifier[idx] = null;
51+
this.draw();
6052
}
6153

62-
// console.log('setUniform: ', name, value, position, slow);
63-
const uniform = instance.uniforms[name];
64-
if (uniform) {
65-
let uniformValue;
66-
if (uniform.count == 0) {
67-
// This is a single value
68-
uniformValue = uniform.value;
54+
set(value, pos = 0) {
55+
const idx = pos % this.value.length;
56+
if (typeof value === 'function') {
57+
this.frameModifier[idx] = value;
6958
} else {
70-
// This is an array
71-
const idx = position % uniform.value.length;
72-
uniformValue = uniform.value[idx];
59+
this.value[idx] = value;
60+
this.frameModifier[idx] = null;
7361
}
74-
uniformValue.slow = slow;
75-
if (incr) uniformValue.desired += value;
76-
else uniformValue.desired = value;
77-
} else {
78-
logger('[shader] unknown uniform: ' + name);
62+
this.draw();
63+
}
64+
65+
get(pos = 0) {
66+
return this.value[pos % this.value.length];
67+
}
68+
69+
_frameUpdate(elapsed) {
70+
this.value = this.value.map((value, idx) =>
71+
this.frameModifier[idx] ? this.frameModifier[idx](value, elapsed) : value,
72+
);
73+
return this.isArray ? this.value : this.value[0];
7974
}
8075

81-
// Ensure the instance is drawn
82-
instance.age = 0;
83-
if (!instance.drawing) {
84-
instance.drawing = requestAnimationFrame(instance.update);
76+
_resize(count) {
77+
if (count != this.count) {
78+
this.isArray = count > 0;
79+
count = Math.max(1, count);
80+
resizeArray(this.value, count, 0);
81+
resizeArray(this.frameModifier, count, null);
82+
}
8583
}
8684
}
8785

88-
// Update the uniforms for a given drawFrame call.
89-
function updateUniforms(drawFrame, elapsed, uniforms) {
90-
Object.values(uniforms).forEach((uniform) => {
91-
const value = uniform.count == 0 ? uniform.value.get(elapsed) : uniform.value.map((v) => v.get(elapsed));
86+
// Shrink or extend an array
87+
function resizeArray(arr, size, defval) {
88+
if (arr.length > size) arr.length = size;
89+
else arr.push(...new Array(size - arr.length).fill(defval));
90+
}
9291

93-
// Send the value to the GPU
94-
// console.log('updateUniforms:', uniform.name, value);
95-
drawFrame.uniform(uniform.name, value);
96-
});
92+
// Get the size of an uniform
93+
function uniformSize(funcName) {
94+
if (funcName == 'uniform3fv') return 3;
95+
else if (funcName == 'uniform4fv') return 4;
96+
return 1;
9797
}
9898

9999
// Setup the instance's uniform after shader compilation.
100-
function setupUniforms(uniforms, program) {
101-
Object.entries(program.uniforms).forEach(([name, uniform]) => {
100+
function setupUniforms(instance) {
101+
const newUniforms = new Set();
102+
Object.entries(instance.program.uniforms).forEach(([name, uniform]) => {
102103
if (name != 'iTime' && name != 'iResolution') {
103104
// remove array suffix
104105
const uname = name.replace('[0]', '');
105-
const count = uniform.count | 0;
106-
if (!uniforms[uname] || uniforms[uname].count != count) {
107-
// TODO: keep the previous values when the count change:
108-
// if the count decreased, then drop the excess, else append new values
109-
uniforms[uname] = {
110-
name,
111-
count,
112-
value: count == 0 ? new UniformValue() : new Array(count).fill().map(() => new UniformValue()),
113-
};
114-
}
106+
newUniforms.add(uname);
107+
const count = (uniform.count | 0) * uniformSize(uniform.glFuncName);
108+
if (!instance.uniforms[uname])
109+
instance.uniforms[uname] = new UniformValue(name, count, () => {
110+
// Start the drawing loop
111+
instance.age = 0;
112+
if (!instance.drawing) {
113+
instance.drawing = requestAnimationFrame(instance.update);
114+
}
115+
});
116+
else instance.uniforms[uname]._resize(count);
115117
}
116118
});
117-
// TODO: remove previous uniform that are no longer used...
118-
return uniforms;
119+
120+
// Remove deleted uniforms
121+
Object.keys(instance.uniforms).forEach((name) => {
122+
if (!newUniforms.has(name)) delete instance.uniforms[name];
123+
});
124+
}
125+
126+
// Update the uniforms for a given drawFrame call.
127+
function updateUniforms(drawFrame, elapsed, uniforms) {
128+
Object.values(uniforms).forEach((uniform) => {
129+
const value = uniform._frameUpdate(elapsed);
130+
131+
// Send the value to the GPU
132+
// console.log('updateUniforms:', uniform.name, value);
133+
drawFrame.uniform(uniform.name, value);
134+
});
119135
}
120136

121137
// Setup the canvas and return the WebGL context.
@@ -156,8 +172,8 @@ async function initializeShaderInstance(name, code) {
156172
.createPrograms([vertexShader, code])
157173
.then(([program]) => {
158174
const drawFrame = app.createDrawCall(program, arrays);
159-
const instance = { app, code, program, arrays, drawFrame, uniforms: setupUniforms({}, program) };
160-
175+
const instance = { app, code, program, arrays, drawFrame, uniforms: {} };
176+
setupUniforms(instance);
161177
// Render frame logic
162178
let prev = performance.now() / 1000;
163179
instance.age = 0;
@@ -189,8 +205,8 @@ async function reloadShaderInstanceCode(instance, code) {
189205
return instance.app.createPrograms([vertexShader, code]).then(([program]) => {
190206
instance.program.delete();
191207
instance.program = program;
192-
instance.uniforms = setupUniforms(instance.uniforms, program);
193208
instance.drawFrame = instance.app.createDrawCall(program, instance.arrays);
209+
setupUniforms(instance);
194210
});
195211
}
196212

@@ -207,4 +223,5 @@ export async function loadShader(code = '', name = 'default') {
207223
await reloadShaderInstanceCode(_instances[name], code);
208224
logger('[shader] reloaded');
209225
}
226+
return _instances[name];
210227
}

packages/shader/uniform.mjs

Lines changed: 0 additions & 125 deletions
This file was deleted.

test/__snapshots__/examples.test.mjs.snap

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8343,36 +8343,6 @@ exports[`runs examples > example "undegradeBy" example index 1 1`] = `
83438343
]
83448344
`;
83458345

8346-
exports[`runs examples > example "uniform" example index 0 1`] = `
8347-
[
8348-
"[ ~show() {
8349-
return this.begin.show() + '' + this.end.show();
8350-
} | pan:0.4999999999999998 ]",
8351-
]
8352-
`;
8353-
8354-
exports[`runs examples > example "uniform" example index 1 1`] = `
8355-
[
8356-
"[ 0/1 → 1/1 | gain:0.5 ]",
8357-
"[ 1/1 → 2/1 | gain:0.3 ]",
8358-
"[ 2/1 → 3/1 | gain:0.5 ]",
8359-
"[ 3/1 → 4/1 | gain:0.3 ]",
8360-
]
8361-
`;
8362-
8363-
exports[`runs examples > example "uniform" example index 2 1`] = `
8364-
[
8365-
"[ 0/1 → 1/2 | s:bd ]",
8366-
"[ 1/2 → 1/1 | s:sd ]",
8367-
"[ 1/1 → 3/2 | s:bd ]",
8368-
"[ 3/2 → 2/1 | s:sd ]",
8369-
"[ 2/1 → 5/2 | s:bd ]",
8370-
"[ 5/2 → 3/1 | s:sd ]",
8371-
"[ 3/1 → 7/2 | s:bd ]",
8372-
"[ 7/2 → 4/1 | s:sd ]",
8373-
]
8374-
`;
8375-
83768346
exports[`runs examples > example "unison" example index 0 1`] = `
83778347
[
83788348
"[ 0/1 → 1/12 | note:d s:supersaw unison:1 ]",

test/runtime.mjs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,6 @@ const toneHelpersMocked = {
7777
strudel.Pattern.prototype.osc = function () {
7878
return this;
7979
};
80-
strudel.Pattern.prototype.uniform = function () {
81-
return this;
82-
};
8380
strudel.Pattern.prototype.csound = function () {
8481
return this;
8582
};

0 commit comments

Comments
 (0)