mathr / blog / #

fl4m6e in Haskell

fl4m6e in Haskell

Last month I was hacking on some C code, being a little OpenGL fractal flame renderer, with stated aims:

... port it from C to Haskell, and do some fancy stuff with generating appropriate GLSL shader source at runtime ...

Well, this month I've done some of that, resulting in some short fl4m6e video loops, and a couple of longer videos r1341, r1341. Read The Fractal Flame Algorithm by Scott Draves and Erik Reckase for more details on the terminology in use below, and for more details on the algorithms involved.

The ./Fl4m6e executable takes arguments on the commandline specifying which variations to use, and which symmetry to apply. For example:

./Fl4m6e [[Bent],[Polar],[Linear,Exponential]] -4
./Fl4m6e [[Horseshoe],[Horseshoe],[Horseshoe]] 5
./Fl4m6e [[Horseshoe],[Fisheye,Bubble],[Linear]] -6

./Fl4m6e will generate some shader source code that will do the calculations corresponding to that fractal flame structure, including some slots for pre- and post-matrix, variational-weight and colour coefficients that are to be animated later. Note that dependent and parametric variations are not yet supported, nor are ones requiring noise. Also note that shaders may fail to work if they are too complex for your hardware, so don't use too many expensive varations - maybe it will be possible to use lookup table textures for more intensive operations like trigonometric functions.

./Fl4m6e will combine snippets for each variation used, along with a scafold that plays the chaos game, into a fragment shader that will run on the GPU. Symmetries are specified by an integer specifying the order of rotational symmetry, negated if mirror symmetry is also desired. The symmetry matrices are compiled into a second fragment shader.

Animation is achieved by generating pseudo-random coffecients (in a structure with the same "shape" as the particular flame structure being rendered) and interpolating between them, initially made easier with an Applicative instance for the FlameDynamic type and a liftA4 implementation. However, as the visual appearance of naive coordinate-wise interpolation of matrices is a bit rubbish, I looked for a better way - and found it in As Rigid As Possible Shape Interpolation. Awesome! The loops above were rendered without this enhancement, however - you'll have to watch the longer one to see the improvement.

Source code is available under AGPL3+ license, but be warned it's under development, and some versions will spew out binary image data on stdout, so read through before trying it out! Eventually I hope to get Fl4m6e on Hackage, the GLEW requirement might make that trickier, meanwhile:

svn checkout

EDIT: Between r1333 and r1341 I fixed a bad "insufficient randomness" bug - with the fix the generated image quality is vastly superior - easy to tell uncompressed/live, not quite so easy to spot the difference between the videos amidst all the other changes.