Live coding (fluxus) captured my interest. Evolutionary programming a game system using scheme will be a nice pet project to experiment with.
PLT-Scheme
Checking out different versions of scheme i stumbled upon gambit and ypsilon and plt-scheme. After some deliberation i chose plt-scheme. Nicely organised, good documentation and standard libraries and big community. Very active irc channel on irc.freenode.org #scheme which answered my questions within 5 minutes.
Wikipedia describes PLT scheme in a nice fashion:
From the beginning, the PLT project was also an experiment in evaluating the suitability of Scheme as a programming language for large projects. In a sense, the language failed and yet it also proved to be an ideal platform. Scheme per se failed because the standard language, as defined in the reports, is too small for a team of 20-30 developers, distributed across three continents. If taken as an ideal kernel, however, Scheme succeeded beyond the team's expectations.
We need a window to run our app in
PLT Scheme has a gui toolkit which can be loaded with.
(require scheme/gui/base)
This library needs primitive graphics support at runtime an cannot
be executed with mzscheme
. For these programs we have mred
.
MzScheme, MrEd, PLT's graphical user toolkit
As I understand it, PLT-Scheme has mzscheme as an ideal lightweight scripting environment. And MrEd for GUI based apps.
mred -iz -l readline -l scheme/enter
We load 2 libraries not standard included in my version of mred
:
readline
, up/down, tab-completion etcscheme/enter
, to be able to reload modules and change evaluation contexts, providesenter!
procedure.
Windowing time
The gui/base consist of an hierarchy of classes, interesting for us are:
- canvas%, a general-purpose window for drawing and handling events.
- frame%, a top-level container window. It has a title bar (which displays the frame's label), an optional menu bar, and an optional status line.
Every painter needs a canvas
For our app to at least draw anything we need an opengl ready canvas. The window should also be able to recognize size changes and a method to actually draw something on our canvas.
the functions resize
and paint
will be defined later.
(define gl-canvas%
(class* canvas% ()
(inherit with-gl-context swap-gl-buffers)
(define/override (on-paint)
(with-gl-context
(lambda ()
(paint)
(swap-gl-buffers))))
(define/override (on-size width height)
(with-gl-context
(lambda ()
(resize width height))))
(super-instantiate () (style '(gl)))))
Without the frame we cannot hang the painting
Our canvas needs to framed for the os to display it.
(define window
(new frame% (label "Minimal") (min-width 200) (min-height 200)))
Rendering time
Now we have setup a minimal frame with a canvas which is opengl ready. Now we
can execute OpenGl calls to actually start drawing. resize
is called on a
resize and since this is minimal does nothing. paint
is called when the
canvas is exposed or resized so that the image in the canvas can be repainted.
;; gl-canvas functions resise and main draw
(define (resize w h) #t)
(define (paint)
(glClearColor 0.0 0.0 0.0 0.0)
(glClear GL_COLOR_BUFFER_BIT)
(glColor3d 1.0 1.0 1.0)
(glMatrixMode GL_PROJECTION)
(glLoadIdentity)
(glOrtho 0.0 1.0 0.0 1.0 -1.0 1.0)
(glMatrixMode GL_MODELVIEW)
(glLoadIdentity)
(glBegin GL_QUADS)
(glVertex3d 0.25 0.25 0.0)
(glVertex3d 0.75 0.25 0.0)
(glVertex3d 0.75 0.75 0.0)
(glVertex3d 0.25 0.75 0.0)
(glEnd)
)
Putting it all together
To actually create the frame canvas, and fire the on-paint and on-size triggers send the window instance the show message. This should create all.
;; show window
(send window show #t)
And now for live coding!
The essential element here is the live coding. This is accomplished by changing the paint function and sending it to your repl. First we need to change the evaluation context. This is done by:
(enter! "minimal.ss")
and redefining paint
:
(define (paint)
(glClearColor 0.0 0.0 0.0 0.0)
(glClear GL_COLOR_BUFFER_BIT)
(glColor3d 0.0 1.0 1.0)
(glMatrixMode GL_PROJECTION)
(glLoadIdentity)
(glOrtho 0.0 1.0 0.0 1.0 -1.0 1.0)
(glMatrixMode GL_MODELVIEW)
(glLoadIdentity)
(glBegin GL_QUADS)
(glVertex3d 0.25 0.25 0.0)
(glVertex3d 0.75 0.25 0.0)
(glVertex3d 0.75 0.75 0.0)
(glVertex3d 0.25 0.75 0.0)
(glEnd)
)
now change size of the window to trigger a on-paint
and the colour of the
square changes. The basic elements of live coding are accomplished.