diff options
| author | s-ol <s+removethis@s-ol.nu> | 2025-04-05 17:48:08 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2025-04-07 10:33:17 +0000 |
| commit | 6d05263540b4a50f8d2ccb70b69ed6760e2ab691 (patch) | |
| tree | 36c130068e18712181a6d7db095ed8092d12b694 /alv-lib | |
| parent | propagate dynamic scope in require/import (diff) | |
| download | alive-6d05263540b4a50f8d2ccb70b69ed6760e2ab691.tar.gz alive-6d05263540b4a50f8d2ccb70b69ed6760e2ab691.zip | |
template strings as syntax sugar for Ops
Diffstat (limited to 'alv-lib')
| -rw-r--r-- | alv-lib/glsl-view.moon | 132 |
1 files changed, 75 insertions, 57 deletions
diff --git a/alv-lib/glsl-view.moon b/alv-lib/glsl-view.moon index c2d57ee..e0b8678 100644 --- a/alv-lib/glsl-view.moon +++ b/alv-lib/glsl-view.moon @@ -1,4 +1,4 @@ -import Constant, Op, TemplateString, Input, T, Array, Struct, sig, const from require 'alv.base' +import Constant, PureOp, Op, template_subst, Input, T, Array, Struct, sig, const from require 'alv.base' import Message, Bundle, Timetag, add_item from require 'alv-lib._osc' import dns, udp from require 'socket' @@ -107,86 +107,103 @@ tsv_input = Constant.meta with @inputs.socket! \send Message.pack { address: "/texture/#{name}/tsv", types: "ss", "TEXTURE_#{type}", name } -shader = Constant.meta +shader_ = Constant.meta meta: name: 'shader' - summary: "control a GLSL shader via OSC." - examples: { '(shader [socket] code-tpl-str)' } + summary: "compile a GLSL shader with uniforms." + examples: { '#shader"code…"' } description: "Syncs code and parameters with glsl-view via OSC. -- `socket` must be an `osc/out~` or read from `*oscout*` -- `code-tpl-str` is a `str=` that can contain `~-stream` template substitutions - that are mapped as follows: +- `code…` is a template string that can contain `~-stream` template substitutions that are used as follows: - `str`: substituted directly as GLSL - `{type: str val: …}`: reference to uniform of type `type` (instead of infered as follows) - `num`, `bool`: reference to `uniform float/bool` - `num[I]`, `bool[I]`: reference to `uniform vecI/bvecI` - `num[I][J]`: reference to `uniform matIxJ`" - value: class extends Op - pattern = -sig['osc/out'] + const.str + sig!^0 + value: class extends PureOp + pattern: const! + sig!^0 - default_sender = (input) -> input\type!, input! - get_code: => - uniforms = { '#version 330 core' } + name: (i) => "alv_u_#{i}" - @state = {} - code = TemplateString.subst @inputs.code!, (i) -> - param = @inputs.params[i] - type = param\type! - return param! if type == T.str + type: (args) => + uniforms = {} + for i, val in ipairs args[2] + type = val\type! + if type == T.str + continue + elseif type.__class == Struct + assert (type\get 'type') == T.str, "struct substituton needs type key" + type = assert (type\get 'val'), "struct substituton needs val key" - id = tostring math.random! - name = "alv_param_#{id\sub 3}" + uniforms[@name i] = type - typestr = GLSL_TYPES[tostring type] + uniforms = Struct uniforms + Struct shader: T.str, :uniforms - -- NOTE: can't close over @ or input or breaks when forked - if type.__class == Struct - assert type.types.type == T.str, "struct substituton needs type key" - val_type = assert type.types.val, "struct substituton needs val key" + tick: => + uniforms = {} + + preamble = { '#version 330 core' } + pieces = for i, input in ipairs @inputs[2] + name, input = (@name i), input + val, type = input!, input\type! - typestr = param!.type - @state[i] = => "/uniform/#{name}", val_type, @inputs.params[i]!.val + typestr = GLSL_TYPES[tostring type] + if type == T.str + val else + if type.__class == Struct + typestr = val.type + val, type = val.val, val.type + assert typestr, "unsupported type #{type}" - @state[i] = => "/uniform/#{name}", type, @inputs.params[i]! + table.insert preamble, "uniform #{typestr} #{name};" + uniforms[name] = val + name - table.insert uniforms, "uniform #{typestr} #{name};" + shader = template_subst @inputs[1]!, pieces - name + table.insert preamble, shader + shader = table.concat preamble, '\n' - table.insert uniforms, code - table.concat uniforms, '\n' + @out\set :shader, :uniforms - setup: (inputs, scope) => - { socket, code, params } = pattern\match inputs +draw = Constant.meta + meta: + name: 'draw' + summary: "draw a GLSL shader via OSC." + examples: { '(draw [socket] shader)' } + description: "Syncs code and parameters with glsl-view via OSC. +- `socket` must be an `osc/out~` or read from `*oscout*` +- `shader` is a struct~ with + - `shader` (`str`): GLSL source + - `uniforms`: struct mapping uniform names to values" + + value: class extends Op + pattern = -sig['osc/out'] + sig! + + setup: (inputs, scope) => + { socket, shader } = pattern\match inputs super socket: Input.hot socket or scope\get '*oscout*' - code: Input.hot code - params: [Input.hot param for param in *params] - - tick: (setup) => - bundle = Bundle.new Timetag.new! - recompile = setup or @inputs.code\dirty! or @inputs.socket\dirty! - if recompile - bundle\add content: { address: '/shader', types: 's', @get_code! } - - for i, input in ipairs @inputs.params - continue unless recompile or input\dirty! - - if sender = @state[i] - addr, type, val = sender @ - bundle\add with msg = Message.new addr - add_item msg, type, val - elseif not recompile - -- text-only piece is dirty, force recompile - return @tick true - - return unless #bundle.content > 0 - with @inputs.socket! - \send Bundle.pack bundle.content + shader: Input.hot shader + + tick: => + { :socket, :shader } = @unwrap_all! + + with Bundle.new Timetag.new! + \add content: { address: '/shader', types: 's', shader.shader } + + types = @inputs.shader\type!\get 'uniforms' + for key, val in pairs shader.uniforms + type = types\get key + msg = Message.new "/uniform/#{key}" + add_item msg, type, val + \add msg + + socket\send Bundle.pack .content Constant.meta meta: @@ -197,4 +214,5 @@ Constant.meta :video 'tsv-input': tsv_input :texture - :shader + shader: shader_ + :draw |
