diff --git a/packages/shader/shader.mjs b/packages/shader/shader.mjs index 5fd811852..02c68d722 100644 --- a/packages/shader/shader.mjs +++ b/packages/shader/shader.mjs @@ -4,6 +4,64 @@ Copyright (C) 2024 Strudel contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ +/* +/// Here is a feature demo +// Setup a shader +let truchetFTW = await fetch('https://raw.githubusercontent.com/TristanCacqueray/shaders/refs/heads/main/shaders/Truchet%20%2B%20Kaleidoscope%20FTW.glsl').then((res) => res.text()) +// This shader provides the following uniforms: +// uniform float icolor; +// uniform float moveFWD; +// uniform float rotations[4]; +// uniform float modulations[6]; + +// Start the instance and binds the uniforms +let {uniforms} = await loadShader(truchetFTW) + +setcpm(96) + +// A smoothing function that is called for each frame +let smooth = (desired, speed) => (value) => value + ((desired - value) / speed) + +// Each kick updates a different rotation value. +let rotationIndex = 0 +$: s("bd").bank("RolandTR808") + .gain(2).dist("<1 .7 .7 .7>") + .mask("<1@30 0@2>") + .onTrigger(() => uniforms.rotations.set( + cur => smooth(cur + 1, 20), rotationIndex++), + false) + +// Each hat increase the icolor value. +$: sound("hh*4").bank("RolandTR808") + .room(.3).gain(".25 .3 .4") + .mask("<0@8 1@32>") + .onTrigger(() => uniforms.icolor.incr(0.1), false) + +// The snare smoothly increase the moveFWD value +$: s("cp/8").bank("RolandTR808") + .hpf(500).hpa(.8).hpenv("<-3 -2 -3 -2 -1>/8") + .room(0.5).roomsize(7).rlp(5000).gain(.2) + .onTrigger(() => uniforms.moveFWD.set(cur => smooth(cur + 1, 30)), false) + +// Each piano note updates a different modulations value +let pianoPitches = {} +$: note("*[2,2.02]") + .clip(1.1) + .transpose("<-12 -24 -12 0>/8") + // .sound("sawtooth") + .sound("triangle") + .cutoff(perlin.slow(5).range(20,1200)) + .room(.8).roomsize(.6) + .gain(.4) + .onTrigger((_, hap) => { + const n = hap.value.note + // assign unique array position for each new notes + if (!pianoPitches[n]) pianoPitches[n] = Object.keys(pianoPitches).length + 1 + const idx = pianoPitches[n] + uniforms.modulations.set(cur => smooth(cur + .5, 55), idx) + }, false) +*/ + import { PicoGL } from 'picogl'; import { logger } from '@strudel/core'; @@ -51,10 +109,11 @@ class UniformValue { this.draw(); } + // The value can be a function that will be called for each rendering frame set(value, pos = 0) { const idx = pos % this.value.length; if (typeof value === 'function') { - this.frameModifier[idx] = value; + this.frameModifier[idx] = value(this.value[idx]); } else { this.value[idx] = value; this.frameModifier[idx] = null; @@ -127,11 +186,16 @@ function setupUniforms(instance, resetDraw = false) { // Update the uniforms for a given drawFrame call. function updateUniforms(drawFrame, elapsed, uniforms) { Object.values(uniforms).forEach((uniform) => { - const value = uniform._frameUpdate(elapsed); + try { + const value = uniform._frameUpdate(elapsed); - // Send the value to the GPU - // console.log('updateUniforms:', uniform.name, value); - drawFrame.uniform(uniform.name, value); + // Send the value to the GPU + // console.log('updateUniforms:', uniform.name, value); + drawFrame.uniform(uniform.name, value); + } catch (err) { + console.warn('uniform error'); + console.error(err); + } }); } @@ -207,6 +271,7 @@ async function reloadShaderInstanceCode(instance, code) { instance.program.delete(); instance.program = program; instance.drawFrame = instance.app.createDrawCall(program, instance.arrays); + instance.code = code; setupUniforms(instance, true); }); }