This week I got first class functions into CEPL. It’s not release quality yet but it seems to work which is ace.

What I can now do is define a pipeline that takes a function as a uniform. It compiles this to typecheck it but GLSL doesn’t support first-class functions so the pipeline is marked as partial.

So if I have a gpu function I’m going to use as my fragment shader in some particle system:

(defun-g update-particle-velocities ((tex-coord :vec2)
                                     &uniform (positions :sampler-2d)
                                              (velocities :sampler-2d)
                                              (animator (function (:vec4 :vec4) :vec4)))
  (let* ((position (texture positions tex-coord))
         (velocity (texture velocities tex-coord)))
    ;; calc the new velocity
    (funcall animator positions velocities)))

I can make a partial pipeline:

(def-g-> update-velocities ()
   :vertex (full-screen-quad :vec4)
   :fragment (update-particle-velocities :vec2))

If I try and run this CEPL will complain that this is partial. Now let’s make a dumb function that slowly pulls all particles to the origin:

(defun-g origin-sink ((pos :vec4) (vel :vec4))
  (let ((dif (- pos)))
     (+ velocity (* (normalize dif) (sqrt (length dif)) 0.001))))

And now we can complete the pipeline:

(defvar new-pipeline (bake 'update-velocities :animator '(origin-sink :vec4 :vec4)))

I’m not happy with the syntax yet but the effect is to create a new pipeline with the uniform animator permanently set to our origin-sink function.

We can then map over that new pipeline like any other:

(map-g new-pipeline quad-verts :positions pos-sampler :velocities vel-sampler)

The advantage of this is that I can make a bunch of different ‘animator’ functions and make pipelines that use them just with bake. It still feels odd to me though so It’ll take some time to get used to and cleaned up.

One thing that is interesting me recently is that in livecoding it almost encourages more ‘static’ code. Composition is great for programming but to a degree makes things opaque to the experimenter. If you call a function that returns a function you are sitting in the repl with this function with very little insight into what it is/does. You have to maintain that mapping yourself. It may have something lexically captured, it may not.. I’m not sure where I’m going with this, expect that maybe it would be cool to be able to get the code that made the lambda while at the repl so you can get some context.

Anyhoo, this next week I need to work on the compiler a bit, clean up some of the stuff above & do spend some time studying.


Published: December 28 2016

  • category:
blog comments powered by Disqus