diff options
| author | s-ol <s+removethis@s-ol.nu> | 2025-03-15 15:42:15 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2025-03-18 11:05:10 +0000 |
| commit | 62b70c808c9abebb4734232c30a65239d6ec0be3 (patch) | |
| tree | ead393ef58af3b5417cbf3edbcfb227711e168bd | |
| parent | lib: support receiving OSC (diff) | |
| download | alive-62b70c808c9abebb4734232c30a65239d6ec0be3.tar.gz alive-62b70c808c9abebb4734232c30a65239d6ec0be3.zip | |
lib: add glsl-view
| -rw-r--r-- | alv-lib/_osc.moon | 9 | ||||
| -rw-r--r-- | alv-lib/glsl-view.moon | 128 | ||||
| -rw-r--r-- | alv-lib/link-time.moon | 34 | ||||
| -rw-r--r-- | docs/gen/shim.moon | 5 |
4 files changed, 173 insertions, 3 deletions
diff --git a/alv-lib/_osc.moon b/alv-lib/_osc.moon index 265be9e..ba78629 100644 --- a/alv-lib/_osc.moon +++ b/alv-lib/_osc.moon @@ -1,6 +1,9 @@ -import new_message from require 'losc' +import new_message, new_bundle from require 'losc' import opairs from require 'alv.util' import T, Array, Struct from require 'alv.base' +Message = require 'losc.message' +Bundle = require 'losc.bundle' +Timetag = require 'losc.timetag' add_item = (message, type, val, use_arrays=false) -> switch type.__class @@ -27,5 +30,9 @@ add_item = (message, type, val, use_arrays=false) -> { :new_message + :new_bundle :add_item + :Message + :Bundle + :Timetag } diff --git a/alv-lib/glsl-view.moon b/alv-lib/glsl-view.moon new file mode 100644 index 0000000..5438cc3 --- /dev/null +++ b/alv-lib/glsl-view.moon @@ -0,0 +1,128 @@ +import Constant, Op, TemplateString, Input, T, Array, sig, const from require 'alv.base' +import Message, Bundle, Timetag, add_item from require 'alv-lib._osc' +import dns, udp from require 'socket' + +ALV_TYPES = {} +GLSL_TYPES = + num: 'float' + bool: 'bool' + +for i=2,4 + GLSL_TYPES["num[#{i}]"] = "vec#{i}" + GLSL_TYPES["bool[#{i}]"] = "bvec#{i}" + + for j=2,4 + GLSL_TYPES["num[#{j}][#{i}]"] = "mat#{i}x#{j}" + +for p in *{'', 'i', 'g'} + ALV_TYPES["glsl/#{p}sampler2D"] = T.str + GLSL_TYPES["glsl/#{p}sampler2D"] = "#{p}sampler2D" + ALV_TYPES["glsl/#{p}sampler2DArray"] = T.str + GLSL_TYPES["glsl/#{p}sampler2DArray"] = "#{p}sampler2DArray" + ALV_TYPES["glsl/#{p}sampler3D"] = T.str + GLSL_TYPES["glsl/#{p}sampler3D"] = "#{p}sampler3D" + +uniform = Constant.meta + meta: + name: 'uniform' + summary: "override uniform binding type." + examples: { '(uniform glsl-type value)' } + description: "Set a specific GLSL type for this value. + +For example to send a string to glsl-view and load an image into a sampler: + + vec4 color = texture(#(uniform 'sampler2D' 'image.png'), uv);" + + value: class extends Op + pattern = const.str + sig! + setup: (inputs, scope) => + { type, value } = pattern\match inputs + + super Input.hot value + + @setup_out '~', T["glsl/#{type.result!}"] + + tick: => @out\set @inputs! + +shader = Constant.meta + meta: + name: 'shader' + summary: "control a GLSL shader via OSC." + examples: { '(shader [socket] code-tpl-str)' } + 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: + - `str`: substituted directly as GLSL + - `num`, `bool`: reference to `uniform float/bool` + - `num[I]`, `bool[I]`: reference to `uniform vecI/bvecI` + - `num[I][J]`: reference to `uniform matIxJ` + - `glsl-view/uniform`: reference to uniform of declared type + +`params` are substituted in `code` as uniforms using TemplateString logic" + + value: class extends Op + pattern = -sig['osc/out'] + const.str + sig!^0 + + get_code: => + uniforms = { '#version 330 core' } + + @state = names: {}, types: {} + code = TemplateString.subst @inputs.code!, (i) -> + param = @inputs.params[i] + typename = tostring param\type! + if typename == 'str' + return param! + + id = tostring math.random! + name = "alv_param_#{id\sub 3}" + + typestr = assert GLSL_TYPES[typename], "unsupported type #{typename}" + table.insert uniforms, "uniform #{typestr} #{name};" + @state.types[i] = ALV_TYPES[typename] or param\type! + @state.names[i] = name + + name + + table.insert uniforms, code + table.concat uniforms, '\n' + + setup: (inputs, scope) => + { socket, code, params } = 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! + + compile = if setup or @inputs.code\dirty! then @get_code! + all = compile or @inputs.socket\dirty! + + for i, input in ipairs @inputs.params + if all or input\dirty! + if name = @state.names[i] + msg = Message.new "/#{name}" + add_item msg, @state.types[i], input! + bundle\add msg + else + compile or= @get_code! + + if compile + msg = { address: '/-/shader', types: 's', compile } + table.insert bundle.content, 1, msg + + with sock = @inputs.socket! + \send Bundle.pack bundle.content + +Constant.meta + meta: + name: 'glsl-view' + summary: "glsl-view integration via OSC." + + value: + :shader + :uniform diff --git a/alv-lib/link-time.moon b/alv-lib/link-time.moon index 1568b49..34e2220 100644 --- a/alv-lib/link-time.moon +++ b/alv-lib/link-time.moon @@ -210,6 +210,39 @@ tick = Constant.meta vis: => type: 'event' +phase = Constant.meta + meta: + name: 'phase' + summary: "Get phase." + examples: { '(tick [clock] period)' } + description: "Counts upwards by one every `period` beats. + +- `clock` should be a `link/clock~` stream. This argument can be omitted + and the stream be passed as a dynamic definition in `*clock*` instead. +- `period` should be a num~ stream and defaults to 1. +- returns a `num~` stream that ticks from 0 to `period`." + value: class extends Op + pattern = -sig['link/clock'] + -sig.num + -sig.num + setup: (inputs, scope) => + { clock, period, phase } = pattern\match inputs + super + clock: Input.hot clock or scope\get '*clock*' + period: Input.cold period or Constant.num 0 + phase: Input.cold phase or Constant.num 0 + + @setup_out '~', T.num + + tick: => + { :clock, :period, :phase, :evt } = @unwrap_all! + return if period == 0 + + t = clock.state\phase_at_time clock.time, period + t = (t + period - phase) % period + + @out\set t + + vis: => type: 'event' + Constant.meta meta: @@ -222,3 +255,4 @@ Constant.meta :lfo :ramp :tick + :phase diff --git a/docs/gen/shim.moon b/docs/gen/shim.moon index e8a4f08..6d8fbe9 100644 --- a/docs/gen/shim.moon +++ b/docs/gen/shim.moon @@ -4,9 +4,10 @@ export require require = do old_require = require - blacklist = {k, true for k in *{'losc', 'socket', 'system', 'luartmidi', 'abletonlink'}} + blacklist = {'^losc', '^socket$', '^system$', '^luartmidi$', '^abletonlink$'} (mod, ...) -> - return {} if blacklist[mod] + for pat in *blacklist + return {} if mod\match pat old_require mod, ... get_module = (name) -> |
