Skip to content

Commit

Permalink
Refactor the uniform function and add documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
TristanCacqueray committed Oct 19, 2024
1 parent 5c983ce commit b0149f8
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 16 deletions.
15 changes: 14 additions & 1 deletion packages/shader/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# @strudel/shader

Helpers for drawing shader
Helpers for drawing shader.

## Todos

Here are the things that needs to be implemented:

- [ ] Shader source error reporting
- [ ] Shader import from url, like shadertoy or git
- [ ] Display attribution
- [ ] Compilation error reporting, e.g. to show the line number
- [ ] Multiple instance and custom canvas position
- [ ] Multiple program, to be swapped like a pattern
- [ ] Texture inputs
- [ ] Buffer inputs, e.g. to generate a texture
2 changes: 1 addition & 1 deletion packages/shader/index.mjs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export {loadShader} from './shader.mjs';
export * from './shader.mjs';
export * from './uniform.mjs';
6 changes: 4 additions & 2 deletions packages/shader/shader.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const decayModulation = (decay) => {

// Set an uniform value (from a pattern).
export function setUniform(instanceName, name, value, position) {
const instance = _instances[instanceName || 'default'];
const instance = _instances[instanceName];
if (!instance) {
logger('[shader] not loaded yet', 'warning');
return;
Expand Down Expand Up @@ -104,7 +104,8 @@ function setupUniforms(uniforms, program) {
const uname = name.replace('[0]', '');
const count = uniform.count | 0;
if (!uniforms[uname] || uniforms[uname].count != count) {
// TODO: keep the previous value when the count change...
// TODO: keep the previous values when the count change:
// if the count decreased, then drop the excess, else append new values
uniforms[uname] = {
name,
count,
Expand Down Expand Up @@ -174,6 +175,7 @@ async function initializeShaderInstance(name, code) {
updateUniforms(instance.drawFrame, elapsed, instance.uniforms);

instance.drawFrame.draw();
// After sometime, if no update happened, stop the animation loop
if (instance.age++ < 100) requestAnimationFrame(instance.update);
else instance.drawing = false;
};
Expand Down
72 changes: 60 additions & 12 deletions packages/shader/uniform.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,75 @@ This program is free software: you can redistribute it and/or modify it under th
import { register, logger } from '@strudel/core';
import { setUniform } from './shader.mjs';

export const uniform = register('uniform', (options, pat) => {
// Keep track of the pitches value: Map String Int
const pitches = { _count: 0 };
/**
* Update a shader. The destination name consist of
*
* - the uniform name
* - optional array mapping, either a number or an assignment mode ('seq' or 'pitch')
*
* @name uniform
* @example
* s("bd").uniform("iColor")
* @example
* s("bd").uniform("iColors:seq")
* @example
* note("c3 e3").uniform("iMorph:pitch")
*/
function parseUniformTarget(name) {
if (typeof name === 'string')
return {name, mapping: 'single', position: 0}
else if (name.length == 2) {
const mapping = typeof name[1] === 'string' ? name[1] : 'single'
const position = typeof name[1] === 'string' ? null : name[1]
return {
name: name[0],
mapping,
position
}
}
}

// Keep track of the pitches value per uniform
let _pitches = {}
export const uniform = register('uniform', (target, pat) => {
// TODO: support multiple shader instance
const instance = "default"

// Decode the uniform defintion
const uniformTarget = parseUniformTarget(target)

// Get the pitches
if (!_pitches[uniformTarget.name])
_pitches[uniformTarget.name] = {_count: 0}
const pitches = _pitches[uniformTarget.name]

return pat.onTrigger((time_deprecate, hap, currentTime, cps, targetTime) => {
const instance = options.instance;
// TODO: figure out how to get the desired value, e.g. is this pattern for pan, gain, velocity, ...
const value = hap.value ? (hap.value.gain || 1.0) : 1.0;

const value = options.gain || 1.0;
if (options.pitch !== undefined) {
// Get the uniform mapping position
let position = null
if (uniformTarget.mapping == 'pitch') {
// Assign one position per pitch
const note = hap.value.note || hap.value.s;
if (pitches[note] === undefined) {
// Assign new value, the first note gets 0, then 1, then 2, ...
pitches[note] = Object.keys(pitches).length;
}
setUniform(instance, options.pitch, value, pitches[note]);
} else if (options.seq !== undefined) {
setUniform(instance, options.seq, value, pitches._count++);
} else if (options.uniform !== undefined) {
setUniform(instance, options.uniform, value);
position = pitches[note]
} else if (uniformTarget.mapping == 'seq') {
console.log("HERE", pitches)
// Assign a new position per event
position = pitches._count++
} else if (uniformTarget.mapping == 'single') {
// Assign a fixed position
position = uniformTarget.position
} else {
console.error('Unknown shader options, need either pitch or uniform', options);
console.error('Unknown uniform target', uniformTarget)
}

// Update the uniform
if (position !== null)
setUniform(instance, uniformTarget.name, value, position);
}, false);
});

0 comments on commit b0149f8

Please sign in to comment.