aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2025-08-04 23:00:18 +0000
committers-ol <s+removethis@s-ol.nu>2025-08-04 23:00:18 +0000
commit12153d43224fa2a58cedad4497a5c4020b233cf1 (patch)
tree6edc0c85bd770ecfc9ceecac9fddd0c3b076f021
parentdocs: small fixes in guide and reference (diff)
downloadalive-12153d43224fa2a58cedad4497a5c4020b233cf1.tar.gz
alive-12153d43224fa2a58cedad4497a5c4020b233cf1.zip
lib/glsl-view: align source names, add stream source
-rw-r--r--alv-lib/glsl-view.moon110
-rw-r--r--examples/glsl-view/simple.alv12
-rw-r--r--examples/glsl-view/stream.alv20
-rw-r--r--examples/love-glsl-view-tsv.alv26
4 files changed, 148 insertions, 20 deletions
diff --git a/alv-lib/glsl-view.moon b/alv-lib/glsl-view.moon
index e0b8678..8b3ec3f 100644
--- a/alv-lib/glsl-view.moon
+++ b/alv-lib/glsl-view.moon
@@ -2,6 +2,10 @@ import Constant, PureOp, Op, template_subst, Input, T, Array, Struct, sig, const
import Message, Bundle, Timetag, add_item from require 'alv-lib._osc'
import dns, udp from require 'socket'
+tryprefix = (prefix, filename) ->
+ return filename unless prefix and filename\match '^%./'
+ prefix .. filename
+
GLSL_TYPES =
num: 'float'
bool: 'bool'
@@ -29,9 +33,9 @@ uniform = Constant.meta
name: 'uniform'
summary: "override uniform binding type."
examples: { '(uniform glsl-type value)' }
- description: "Generates a struct as received by [shader][]:
+ description: "Generates a uniform struct as received by [glsl-view/shader][]:
-`(uniform 'sampler2D' 'image.png')` is equivalent to `{'type' 'sampler2d' 'val' 'image.png'}`."
+`(uniform 'sampler2D' 'sampler-name')` is equivalent to `{'type' 'sampler2D' 'val' 'sampler-name'}`."
value: class extends Op
pattern = sig.str + sig!
@@ -47,46 +51,108 @@ uniform = Constant.meta
tick: =>
@out\set @unwrap_all!
-video = Constant.meta
+video_source = Constant.meta
meta:
name: 'video'
summary: "load a video texture source."
- examples: { '(video [socket] name filename [type])' }
+ examples: { '(video-source [socket] name type filename [format] [args])' }
+ description: "Creates a texture source from a video or image file.
+
+- `name` is a unique name for this texture source.
+- `type` can be one of:
+ - `2D`: `sampler2D` (loads first frame only)
+ - `3D` or `2D_ARRAY`: `sampler3D`/`sampler2DArray` (loads whole video)
+- `filename` is the video file to load. If it starts with `./` it will be
+ resolved relative to the current alv module.
+- `format` optionally specifies the ffmpeg/avformat input format to use.
+- `args` is a struct of optional arguments for the ffmpeg/avformat input format."
value: class extends Op
- pattern = -sig['osc/out'] + const.str + const.str + -const.str
+ pattern = -sig['osc/out'] + const.str + const.str + const.str + -const.str + -const!
setup: (inputs, scope) =>
- { socket, name, filename, type } = pattern\match inputs
+ { socket, name, type, filename, format, args } = pattern\match inputs
@prefix = COPILOT.active_module.file\match'(.*/)[^/]*$'
super
socket: Input.hot socket or scope\get '*oscout*'
name: Input.cold name
+ type: Input.cold type
filename: Input.cold filename
- type: Input.cold type or Constant.str "2D"
+ format: format and Input.cold format
+ args: args and Input.cold args
samplertype = assert GLSL_SAMPLER_TYPES[@inputs.type!]
@setup_out '=', (Struct type: T.str, val: T.str), type: samplertype, val: @inputs.name!
tick: =>
- { :socket, :name, :type, :filename } = @unwrap_all!
+ { :socket, :name, :type, :filename, :format, :args } = @unwrap_all!
with @inputs.socket!
- if @prefix and not (filename\match '^/') or (filename\match '^%w:\\')
- filename = @prefix .. filename
- \send Message.pack { address: "/texture/#{name}/video", types: "ss", "TEXTURE_#{type}", filename }
+ filename = tryprefix @prefix, filename
+ msg = Message.new{ address: "/texture/#{name}/video", types: "ss", "TEXTURE_#{type}", filename }
+ msg\add 's', format if format
+ add_item msg, @inputs.args\type!, args if args
+ \send Message.pack msg.content
-- destroy: =>
-- name = @inputs.name!
-- with @inputs.socket!
-- \send Message.pack { address: "/texture/#{name}/destroy", types: "" }
-tsv_input = Constant.meta
+stream_source = Constant.meta
+ meta:
+ name: 'stream'
+ summary: "load a stream texture source."
+ examples: { '(stream-source [socket] name type uri [format] [args])' }
+ description: "Creates a realtime stream from a capture source.
+
+- `name` is a unique name for this texture source.
+- `type` must be `2D`.
+- `uri` is the ffmpeg URI to load. If it starts with `./` it will be resolved relative to the current alv module.
+- `format` optionally specifies the ffmpeg/avformat input format to use.
+- `args` is a struct of optional arguments for the ffmpeg/avformat input format.
+
+ (stream-source 'webcam' '2D' '/dev/video0')
+ (stream-source 'testpt' '2D' 'testsrc=size=1280x720:rate=30' 'lavfi')"
+
+ value: class extends Op
+ pattern = -sig['osc/out'] + const.str + const.str + const.str + -const.str + -const!
+ setup: (inputs, scope) =>
+ { socket, name, type, filename, format, args } = pattern\match inputs
+
+ @prefix = COPILOT.active_module.file\match'(.*/)[^/]*$'
+
+ super
+ socket: Input.hot socket or scope\get '*oscout*'
+ name: Input.cold name
+ type: Input.cold type
+ filename: Input.cold filename
+ format: format and Input.cold format
+ args: args and Input.cold args
+
+ samplertype = assert GLSL_SAMPLER_TYPES[@inputs.type!]
+ @setup_out '=', (Struct type: T.str, val: T.str), type: samplertype, val: @inputs.name!
+
+ tick: =>
+ { :socket, :name, :type, :filename, :format, :args } = @unwrap_all!
+
+ with @inputs.socket!
+ filename = tryprefix @prefix, filename
+ msg = Message.new{ address: "/texture/#{name}/stream", types: "ss", "TEXTURE_#{type}", filename }
+ msg\add 's', format if format
+ add_item msg, @inputs.args\type!, args if args
+ \send Message.pack msg.content
+
+tsv_source = Constant.meta
meta:
- name: 'tsv-input'
+ name: 'tsv-source'
summary: "load a texture-share-vk texture source."
- examples: { '(texture [socket] name [type])' }
+ examples: { '(tsv-source [socket] name [type])' }
+ description: "Creates a texture source from a texture-share-vk texture.
+
+- `name` is a unique name for this texture source.
+- `type` defaults to `2D`."
value: class extends Op
pattern = -sig['osc/out'] + const.str + -const.str
@@ -111,12 +177,13 @@ shader_ = Constant.meta
meta:
name: 'shader'
summary: "compile a GLSL shader with uniforms."
- examples: { '#shader"code…"' }
- description: "Syncs code and parameters with glsl-view via OSC.
+ examples: { '$shader"code…"' }
+ description: "A template string formatter for [glsl-view/draw][] that returns a shader struct~.
- `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)
+ - another shader struct~: substituted as GLSL, with uniforms lifted
+ - `{type: str val: …}`: reference to uniform of GLSL-type `type` (instead of inferred 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`"
@@ -211,8 +278,11 @@ Constant.meta
summary: "glsl-view integration via OSC."
value:
- :video
- 'tsv-input': tsv_input
- :texture
+ :uniform
+
+ 'video-source': video_source
+ 'stream-source': stream_source
+ 'tsv-source': tsv_source
+
shader: shader_
:draw
diff --git a/examples/glsl-view/simple.alv b/examples/glsl-view/simple.alv
new file mode 100644
index 0000000..64e3335
--- /dev/null
+++ b/examples/glsl-view/simple.alv
@@ -0,0 +1,12 @@
+([1]import* glsl-view time math)
+([2]import osc)
+
+([3]def *oscout* ([4]osc/connect 'localhost' 9000))
+
+([5]draw $[6]shader"
+in vec2 uv;
+out vec4 color;
+
+void main() {
+ color = vec4(uv, sin(uv.x + $([7]ramp 1 tau)), 1);
+}")
diff --git a/examples/glsl-view/stream.alv b/examples/glsl-view/stream.alv
new file mode 100644
index 0000000..1ca2c63
--- /dev/null
+++ b/examples/glsl-view/stream.alv
@@ -0,0 +1,20 @@
+([1]import* glsl-view time)
+([2]import osc)
+
+([3]def *oscout* ([5]osc/connect 'localhost' 9000))
+
+([6]def cam ([7]stream-source 'webcam' '2D' '/dev/video0')
+ tst ([8]stream-source 'testpt' '2D' 'testsrc=size=1280x720:rate=30' 'lavfi'))
+
+([9]draw $[10]shader"
+in vec2 uv;
+out vec4 color;
+
+void main() {
+ vec3 cam = texture($cam , uv).rgb;
+ vec3 tst = texture($tst , uv).rgb;
+
+ color.rgb = mix(cam, tst, $([11]lfo 1));
+
+ color.a = 1.0;
+}")
diff --git a/examples/love-glsl-view-tsv.alv b/examples/love-glsl-view-tsv.alv
new file mode 100644
index 0000000..344f979
--- /dev/null
+++ b/examples/love-glsl-view-tsv.alv
@@ -0,0 +1,26 @@
+([1]import* love math link-time)
+([2]import osc glsl-view )
+
+([3]def *oscout* ([4]osc/connect 'localhost' 9000)
+ *clock* ([5]clock false 120))
+
+## send from love2d module
+([6]tsv-output 'love2d')
+([7]draw ([8]->>
+ ([16]rectangle 'fill' 100 100)
+ ([14]color [1 0.3 0.6])
+ ([11]rotate ([12]* tau ([13]ramp 2))) ## rotate tau (2*PI) every 2 seconds
+ ([9]translate ([10]mouse-pos)) ## move to mouse cursor
+))
+
+## receive in glsl-view
+([17]def my-tex ([18]glsl-view/tsv-source 'love2d'))
+([19]glsl-view/draw $[20]glsl-view/shader"
+in vec2 uv;
+out vec4 col;
+
+void main() {
+ vec2 p = uv * $([21]switch ([22]every 1) 1 2 3);
+ col = texture($my-tex , p);
+ col.a = 1;
+}")