domingo, 30 de março de 2008

Pure Lisp on X

Um projeto antigo e interessante é o clx, uma implementação do X protocol em Lisp. Nada mais simples para fazer programação gráfica, ele abre um socket com o xserver e manda ver, sem FFI, sem bibliotecas em C, pure lisp on X.

A implementação que funcinou no SBCL (1.0.15) foi a que esta disponível através de:


darcs get http://common-lisp.net/~crhodes/clx


Funciona tanto no Linux quanto no OS X.

Eu fiz um pequeno exemplo que utiliza a minha biblioteca cl-randist. Para executar é preciso pegar a ultima versão com o git:


git clone http://lambdatau.com/git/cl-randist


Depois de instalar as duas bibliotecas, não se esqueça de atualizar os links para o asdf.

O código do programa esta abaixo:


(eval-when (:compile-toplevel)
(require 'clx)
(require 'cl-randist)
(defpackage #:xgauss
(:use #:cl #:xlib :randist)
(:export run)))

(in-package :xgauss)

(defun run (&key (width 400) (height 400) (host ""))
(let* ((display (xlib:open-display host))
(screen (first (xlib:display-roots display)))
(black (xlib:screen-black-pixel screen))
(white (xlib:screen-white-pixel screen))
(root-window (xlib:screen-root screen))

(points (loop for i from 0 to 10000
collect (cons
(floor (random-normal (/ width 2) (/ width 10)))
(floor (random-normal (/ height 2) (/ height 10))))))

(gc (xlib:create-gcontext
:drawable root-window
:foreground black
:background white))

(my-window (xlib:create-window
:parent root-window
:x 0
:y 0
:width width
:height height
:background white
:event-mask (xlib:make-event-mask :exposure
:button-press))))
(xlib:map-window my-window)
(xlib:event-case (display :force-output-p t
:discard-p t)
(:exposure ()
(dolist (pt points)
(xlib:draw-point my-window
gc
(car pt) (cdr pt))))
(:button-press () t))
(xlib:destroy-window my-window)
(xlib:close-display display)))


O resultado é este:




Vejam uma bela nuvem gaussiana :-)

O código é muito simples, a maior parte é burocracia para abrir uma janela e criar um graphic context, toda a ação esta nestes dois trechos, o primeiro que gera 10 mil pontos:


(points (loop for i from 0 to 10000
collect (cons
(floor (random-normal (/ width 2) (/ width 10)))
(floor (random-normal (/ height 2) (/ height 10))))))


E o segundo que manipula os eventos do X:


(xlib:event-case (display :force-output-p t
:discard-p t)
(:exposure ()
(dolist (pt points)
(xlib:draw-point my-window
gc
(car pt) (cdr pt))))
(:button-press () t))

Nenhum comentário: