diff --git a/src/control.html b/src/control.html
index 1adf037..8120fbc 100644
--- a/src/control.html
+++ b/src/control.html
@@ -139,6 +139,7 @@
+
diff --git a/src/control.js b/src/control.js
index 0bbefeb..4dd7f17 100644
--- a/src/control.js
+++ b/src/control.js
@@ -157,7 +157,17 @@ function glbLabel(name) {
: 'Il modello ruota a tempo di musica nella famiglia “Modello 3D”.';
}
if (glbPath) glbLabel(glbPath.split('/').pop());
+// every shader family can be a backdrop too (fluid/interactive/3D excluded:
+// fluids are the explicit options above, the others can't render as layers)
+EFFECTS.families.forEach((name, fi) => {
+ if (/^Interattivo|^Modello 3D|^Fluido/.test(name)) return;
+ const o = document.createElement('option');
+ o.value = 'fam:' + fi;
+ o.textContent = name;
+ $('#glb-bg').appendChild(o);
+});
$('#glb-bg').value = glbBg;
+if (!$('#glb-bg').value) { glbBg = 'gradient'; $('#glb-bg').value = 'gradient'; }
$('#glb-bg').addEventListener('change', (e) => {
glbBg = e.target.value;
localStorage.setItem('glbbg', glbBg);
diff --git a/src/visualizer.js b/src/visualizer.js
index 684a0f8..807f53c 100644
--- a/src/visualizer.js
+++ b/src/visualizer.js
@@ -114,9 +114,21 @@ class Visualizer {
if (e.isModel3d && window.ModelSim) {
if (!this.model3d) this.model3d = new window.ModelSim(gl);
if (this._pendingGlb) { this.model3d.setModel(this._pendingGlb); this._pendingGlb = null; }
- // optional fluid backdrop behind the model (modelBg: ink/fire/ring/...)
+ // optional backdrop behind the model: a fluid mode ('ink'/'fire'/...)
+ // or any shader family ('fam:'), tinted with the active palette
const bg = this.modelBg || 'gradient';
- if (bg !== 'gradient' && window.FluidSim) {
+ if (bg.indexOf('fam:') === 0 && window.EFFECTS) {
+ const fi = parseInt(bg.slice(4), 10);
+ const base = window.EFFECTS.list.find(x => x.family === fi && !x.isFluid && !x.isInteractive && !x.isModel3d);
+ if (base) {
+ const bgEff = Object.assign({}, base, { colorA: e.colorA, colorB: e.colorB,
+ hueBase: e.hueBase, hueCycle: e.hueCycle, sat: e.sat, audioMix: e.audioMix });
+ this._renderUber(timeSec, audio, bgEff);
+ this.model3d.render(timeSec, audio, e, this.canvas, null, true);
+ return;
+ }
+ }
+ if (bg !== 'gradient' && bg.indexOf('fam:') !== 0 && window.FluidSim) {
if (!this.fluid) this.fluid = new window.FluidSim(gl);
this.fluid.render(timeSec, audio, Object.assign({}, e, { fluidMode: bg }), this.canvas);
this.model3d.render(timeSec, audio, e, this.canvas, null, true);
@@ -142,6 +154,12 @@ class Visualizer {
this.fluid.render(timeSec, audio, e, this.canvas);
return;
}
+ this._renderUber(timeSec, audio, e);
+ }
+
+ // The parametric uber-shader pass (also used as a backdrop for the model).
+ _renderUber(timeSec, audio, e) {
+ const gl = this.gl, u = this.u;
gl.useProgram(this.program);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
gl.enableVertexAttribArray(this.aPos);