I am using CAPI:OPENGL-PANE to display some polygons in a window. The
problem I've encountered is when I want to redisplay the pane
independently of any user input. I need to do this since between
redisplaying the pane I rotate the polygons. Ideally, there would be a
way of telling CAPI to call some function a given number of times per
second but I couldn't find it in the docs. So far the only way I found
of achieving this effect is by having the "rotate and redisplay loop"
running in a seperate thread like this.
(defun opengl-demo ()
(let ((interface (capi:display (make-instance 'opengl-interface))))
(loop until *quit*
do
(mp:process-allow-scheduling)
(progn
(setq *angle-of-triangle* (+ *angle-of-triangle* 0.8)
*angle-of-quad* (- *angle-of-quad* 0.6))
(redisplay-canvas (canvas interface)))))
[ In the above code when #'capi:display is called on an instance of
'opengl-interface I believe it creates another thread. Right? ]
When I call the function above everything works but once I close the
window the listener just hangs. It would be nice if I could get this
fixed but I still think the solution lies elsewhere. I shouldn't need
two seperate loops (one inside CAPI running in another thread) to do
this.
Perhaps I shouldn't be using CAPI at all. I don't have any experience
with either CAPI or OpenGL so I'd greatly appreciate any suggestions
you might have. I've enclosed all the code below.
--
Peter
PS. I am using LispWorks 4.1.20 Personal Edition under Windows. I
couldn't get the OpenGL bindings to compile on the Linux version.
(defpackage "DEMO"
(:use "CL" "OPENGL")
(:export "OPENGL-DEMO"))
(in-package "DEMO")
(defparameter *quit* nil)
(capi:define-interface opengl-interface ()
()
(:panes
(canvas capi:opengl-pane
:configuration '(:rgba t :double-buffered t)
:min-width 500
:min-height 300
:display-callback 'redisplay-canvas
:resize-callback 'resize-canvas
:destroy-callback '(lambda () (setq *quit* t))
:reader canvas))
(:layouts
(main capi:column-layout '(canvas) :default t))
(:default-initargs :title "OpenGL Demo"))
(defparameter *angle-of-triangle* 0.0)
(defparameter *angle-of-quad* 0.0)
(defun initialize-canvas ()
(gl-shade-model *gl-smooth*)
(gl-clear-color 0.0 0.0 0.0 0.0)
(gl-clear-depth 1.0)
; (gl-enable *gl-depth-test*)
(gl-depth-func *gl-equal*)
(gl-hint *gl-perspective-correction-hint* *gl-nicest*))
(defun redisplay-canvas (canvas &rest args)
(declare (ignore args))
(rendering-on (canvas)
(initialize-canvas)
(gl-clear *gl-color-buffer-bit*)
(gl-clear *gl-depth-buffer-bit*)
(gl-load-identity)
(gl-translatef -1.5 0.0 -6.0) ;
(gl-rotatef *angle-of-triangle* 0.0 1.0 0.0)
(gl-begin *gl-triangles*)
(gl-color3-f 1.0 0.0 0.0)
(gl-vertex3-f 0.0 1.0 0.0)
(gl-color3-f 0.0 1.0 0.0)
(gl-vertex3-f -1.0 -1.0 0.0)
(gl-color3-f 0.0 0.0 1.0)
(gl-vertex3-f 1.0 -1.0 0.0)
(gl-end)
(gl-load-identity)
(gl-translatef 1.5 0.0 -6.0)
(gl-rotatef *angle-of-quad* 1.0 0.0 0.0)
(gl-color3-f 0.5 0.5 1.0)
(gl-begin *gl-quads*)
(gl-vertex3-f -1.0 1.0 0.0)
(gl-vertex3-f 1.0 1.0 0.0)
(gl-vertex3-f 1.0 -1.0 0.0)
(gl-vertex3-f -1.0 -1.0 0.0)
(gl-end)
(swap-buffers canvas)))
(defun resize-canvas (canvas x y width height)
(declare (ignore x y))
(when #+harlequin-pc-lisp (win32:is-window-visible
(win32:pane-hwnd (capi:representation canvas)))
#-harlequin-pc-lisp T
(rendering-on (canvas)
(gl-viewport 0 0 width height)
(gl-matrix-mode *gl-projection*)
(gl-load-identity)
(glu-perspective 45.0 (coerce (/ width height) 'float) 0.1 100.0)
(gl-matrix-mode *gl-modelview*)
(gl-load-identity))
(redisplay-canvas canvas)))
(defun opengl-demo ()
(let ((interface (capi:display (make-instance 'opengl-interface))))
(loop until *quit*
do
(mp:process-allow-scheduling)
(progn
(setq *angle-of-triangle* (+ *angle-of-triangle* 0.8)
*angle-of-quad* (- *angle-of-quad* 0.6))
(redisplay-canvas (canvas interface)))))
> When I call the function above everything works but once I close the
> window the listener just hangs. It would be nice if I could get this
> fixed but I still think the solution lies elsewhere. I shouldn't need
> two seperate loops (one inside CAPI running in another thread) to do
> this.
To set *quit* , you need to use the :destroy-callback on the interface.
(capi:define-interface opengl-interface ()
()
(:panes
(canvas capi:opengl-pane
:configuration '(:rgba t :double-buffered t)
:min-width 500
:min-height 300
:display-callback 'redisplay-canvas
:resize-callback 'resize-canvas
:reader canvas))
(:layouts
(main capi:column-layout '(canvas) :default t))
(:default-initargs :title "OpenGL Demo"
:destroy-callback #'(lambda (interface)
(setq *quit* t))))
It's also better to use capi:execute-with-interface to check that the
redisplay code runs on the same thread as the thread handling the
events for the interface.
(defun opengl-demo ()
...
(capi-internals:execute-with-interface
interface
#'(lambda ()
(redisplay-canvas (canvas interface))))
...)
[This function is documented in KB:10015
http://www1.xanalys.com/support/lisp/kbase.ns4/51fe6e1cdfe748a180256639005a2ba9
/764b31e4985bcd498525670400530d66!OpenDocument
]
See mp:schedule-timer for data on timers.
Peter Buchlovsky wrote:
> (defun opengl-demo ()
> (let ((interface (capi:display (make-instance 'opengl-interface))))
> (loop until *quit*
> do
> (mp:process-allow-scheduling)
> (progn
> (setq *angle-of-triangle* (+ *angle-of-triangle* 0.8)
> *angle-of-quad* (- *angle-of-quad* 0.6))
> (redisplay-canvas (canvas interface)))))
>
> [ In the above code when #'capi:display is called on an instance of
> 'opengl-interface I believe it creates another thread. Right? ]
>
> When I call the function above everything works but once I close the
> window the listener just hangs. It would be nice if I could get this
> fixed but I still think the solution lies elsewhere. I shouldn't need
> two seperate loops (one inside CAPI running in another thread) to do
> this.
You could use LispWorks timers. See the "MP" package in the
reference-manual.
> PS. I am using LispWorks 4.1.20 Personal Edition under Windows. I
> couldn't get the OpenGL bindings to compile on the Linux version.
The distributed OpenGL bindings are not "Linux ready".
You have to do the following to get them running:
1) change all harlequin-pc-lisp conditionals to win32 in (only!) the
following files:
- compile.lisp
- defsys.lisp
- fns.lisp
- ufns.lisp
- examples/icosahedron.lisp
2) The following form in OPENGL::FIND-X11-VISUAL-INFO
should be changed from
(glx-Choose-Visual display (x-lib:x-screen-number-of-screen screen)
(sys:in-static-area
(make-array (length params) :element-type '(signed-byte 32)
:initial-contents params)))
to
(glx-Choose-Visual display (x-lib:x-screen-number-of-screen screen)
#+harlequin-pc-lisp
(fli:allocate-dynamic-foreign-object :type '(:signed :int)
:initial-contents params)
#-harlequin-pc-lisp
(sys:in-static-area
(make-array (length params) :element-type '(signed-byte 32)
:initial-contents params)))
3) As the dependencies of the libGL and libGLU libraries are missing, you
should do the following:
$ ld -shared -o gl.so -L/usr/X11R6/lib -lGLU -lGL
and then change opengl/load.lisp to contain something like
(fli:register-module "/tmp/gl.so")
My thanks to resolving this problems go to the great Xanalys support-team!
Regards,
Jochen