ShaderStack
I’ve been working on a Concatenative Programming Language which compiles to GLSL for writing fragment shaders. You can play with it at shaders.jordanscales.com.
Concatenative programming languages (sometimes referred to as “catlangs”) have an elegant syntax for function composition: placing words next to each other.
// An example in JavaScript
translateX(scale(p, 2), -1)! An example in factorcode.org
p 2 scale -1 translateX
I’m not very experienced with writing fragment shaders, but some of my favorite examples include
composing various mathematical functions in elegant ways.
composing various mathematical functions in elegant ways.
So, a language where writing composition is pleasant means writing shaders is pleasant. That’s the idea, anyway.
As an example, here’s a solid color in RGBA format.
Toggle shader source Remix this
: main 0.4 0.71 1.0 1.0 vec4 ;
This is roughly equivalent to the following JavaScript.
function main() {
return vec4(0.4, 0.61, 1.0, 1.0);
}
If I want to adjust the blue channel based on the mouse coordinates (or taps on a mobile device), I need to compose vec4 with a mouse position. (Technically, with mouse and resolution getters, and an x-coordinate function)
function main() {
return vec4(0.4, 0.61, getX(mouse() / resolution()), 1.0);
}
With concatenation this is more elegant.
Toggle shader source Remix this
: main
0.4 \ R
0.71 \ G
\ B
mouse resolution / .x
1.0 \ A
vec4
;
And I can extend this further to display a circle with this color, rather than the whole screen. Once I have the “word” to draw a circle, I just shove it in the middle of my program and take the minimum.
Toggle shader source Remix this
:: circle ( p r -- value )
p length
r
step
;
: main
0.4 \ R
0.71 \ G
\ B
mouse resolution / .x
vec3 \ RGB
\ 1 if inside the circle, 0 if outside
uv 0.5 circle
\ Lesser of two vectors
min
1.0 \ A
vec4
;
Thanks for reading! Be sure me know if you make anything cool.
Toggle shader source Remix this
:: mandel-once ( a b a0 b0 -- a b )
\ z => z^2 + c
\ => (a + bi)^2 + (a0 + b0i)
\ => a^2 + 2abi - b^2 + a0 + b0i
\ => a^2 - b^2 + a0 + 2abi + b0i
\ a^2 - b^2 + a0
a a * b b * - a0 +
\ 2ab + b0i
2 a * b * b0 +
;
:: mandel ( a b iter -- length )
0.0 0.0
iter [ a b mandel-once ] times
vec2 length
;
: main
\ -2 to +2
uv 2.0 * dup .x swap .y
\ run 20 iterations
20 mandel
mouse resolution / .x +
mouse resolution / .y +
palette
1.0 vec4
;