fix callback pointer wrapping in glut
[clinton/guile-figl.git] / figl / glut.scm
CommitLineData
61ebde6d
DH
1;;; figl
2;;; Copyright (C) 2013 Daniel Hartwig <mandyke@gmail.com>
3;;;
4;;; Figl is free software: you can redistribute it and/or modify it
5;;; under the terms of the GNU Lesser General Public License as
6;;; published by the Free Software Foundation, either version 3 of the
7;;; License, or (at your option) any later version.
8;;;
9;;; Figl is distributed in the hope that it will be useful, but WITHOUT
10;;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11;;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12;;; Public License for more details.
13;;;
14;;; You should have received a copy of the GNU Lesser General Public
15;;; License along with this program. If not, see
16;;; <http://www.gnu.org/licenses/>.
17
18;;; Commentary:
19;;
7100c070 20;; OpenGL Utility Library (GLUT) binding.
61ebde6d
DH
21;;
22;;; Code:
23
24(define-module (figl glut)
7100c070 25 #:use-module (figl contrib)
d24cc2b8 26 #:use-module (figl glut runtime)
7100c070
DH
27 #:use-module ((figl glut low-level) #:renamer (symbol-prefix-proc '%))
28 #:use-module (figl glut enums)
61ebde6d 29 #:use-module (system foreign)
7100c070
DH
30 #:use-module (srfi srfi-9)
31 #:use-module (srfi srfi-39)) ; parameter objects
32
33(module-use! (module-public-interface (current-module))
34 (resolve-interface '(figl glut enums)))
35
36;;;
37;;; 2 Initialization
38;;;
61ebde6d 39
d24cc2b8
AW
40(re-export (%glutInitWindowPosition . set-initial-window-position)
41 (%glutInitWindowSize . set-initial-window-size)
42 (%glutInitDisplayMode . set-initial-display-mode))
43
44(define glut-init? #f)
61ebde6d 45
d24cc2b8 46(define saved-c-strings '())
61ebde6d
DH
47
48;; Note the use of 'saved-c-strings' to keep a reference to all of the
49;; C string buffers that we ever pass to 'glutInit'. This is important
50;; because the glut docs specify that 'glutInit' wants the original
51;; unmodified 'argv' passed to 'main', which means that it can assume
52;; that the strings will never be freed. 'string->pointer' returns a C
53;; string buffer managed by the garbage collector, which means that
54;; the string may be freed unless the GC can see a pointer to the
55;; _beginning_ of the string.
7100c070 56
d24cc2b8
AW
57(define* (initialize-glut #:optional (args (program-arguments))
58 #:key window-position window-size display-mode)
59 (when glut-init?
60 (error "GLUT already initialized"))
61
62 (when window-position
63 (%glutInitWindowPosition (car window-position) (cdr window-position)))
64
65 (when window-size
66 (%glutInitWindowSize (car window-size) (cdr window-size)))
67
68 (when display-mode
69 (%glutInitDisplayMode display-mode))
70
71 (let* ((num-args (length args))
72 (c-strings (map string->pointer args))
73 (argcp (make-c-struct (list int)
74 (list num-args)))
75 (argv (make-c-struct (make-list (+ 1 num-args) '*)
76 (append c-strings (list %null-pointer)))))
77 (set! saved-c-strings (append c-strings saved-c-strings))
78 (%glutInit argcp argv)
79 (set! glut-init? #t)
80 (let ((argc (car (parse-c-struct argcp (list int)))))
81 (map pointer->string
82 (parse-c-struct argv
83 (make-list argc '*))))))
84
85(add-hook! *resolve-hook*
86 (lambda (name)
87 (unless (or glut-init? (string-prefix? "glutInit" name))
88 (initialize-glut))))
89
90(export initialize-glut)
91
7100c070
DH
92
93;;;
94;;; 3 Beginning Event Processing
95;;;
96
97(re-export (%glutMainLoop . glut-main-loop))
98
99\f
100;;;
101;;; 4 Window Management
102;;;
103
104;; Garbage collected windows are not automatically destroyed. Permit
105;; them to continue living inside GLUT.
106
107(define-record-type window
108 (%%make-window id live?)
109 window?
110 (id window-id)
111 (live? window-live? set-window-live?!))
112
113(define (assert-live-window! window)
114 (unless (window-live? window)
115 (error "window already destroyed" window)))
116
117(define (top-level-window? window)
118 (not (window-parent window)))
119
120(define (sub-window? window)
121 (and (window-parent window)
122 #t))
123
124(define (assert-top-level-window! window)
125 (unless (top-level-window? window)
126 (error "not a top-level window" window)))
127
128;; Memoized so state requests can return the same object.
129(define %make-window (memoize %%make-window))
130
131(define (make-window str)
132 (let ((id (%glutCreateWindow str)))
133 (%make-window id #t)))
134
135(define (make-sub-window window x y width height)
136 (let ((id (%glutCreateSubWindow (window-id window) x y width height)))
137 (%make-window id #t)))
138
139(define (current-window)
140 (let ((ret (%glutGetWindow)))
141 (and (not (zero? ret))
142 (%make-window ret #t))))
143
144(define (set-current-window window)
145 (assert-live-window! window)
146 (let ((old (current-window)))
147 (%glutSetWindow (window-id window))
148 old))
149
150(define (destroy-window window)
151 (set-window-live?! window #f)
152 ;; TODO: Also mark sub-windows.
153 (%glutDestroyWindow (window-id window)))
154
155;; A short detour for some syntax forms, then most window procedures
156;; operate on /either/ current-window or a specified window.
157
158(define (with-window* window thunk)
159 (let* ((swap-windows (lambda ()
160 (set! window (set-current-window window)))))
161 (dynamic-wind swap-windows thunk swap-windows)))
162
163;; emacs: (put 'with-window 'scheme-indent-function 1)
164(define-syntax with-window
165 (syntax-rules ()
166 ((_ window body1 body2 ...)
167 (with-window* window (lambda () body1 body2 ...)))))
168
169;; emacs: (put 'maybe-with-window 'scheme-indent-function 1)
170(define-syntax maybe-with-window
171 (syntax-rules ()
172 ((_ window body1 body2 ...)
173 (if (eqv? window #t) ; use current-window
174 (begin
175 body1 body2 ...)
176 (with-window window
177 (assert-live-window! window)
178 body1 body2 ...)))))
179
180(export with-window*)
181
182(export-syntax with-window)
183
184;; TODO: These post requests, and do not update the window parameters
185;; immediately. Otherwise, names like set-window-position! may be
186;; more appropriate on the Scheme side.
187
188(define (position-window window x y)
189 (maybe-with-window window
190 (%glutPositionWindow x y)))
191
192(define (reshape-window window width height)
193 (maybe-with-window window
194 (%glutReshapeWindow width height)))
195
196(define* (post-redisplay #:optional (window #t))
197 (maybe-with-window window
198 (%glutPostRedisplay)))
199
200(define* (swap-buffers #:optional (window #t))
201 (maybe-with-window window
202 (%glutSwapBuffers)))
203
204(define (full-screen window full-screen?)
205 (if full-screen?
206 (maybe-with-window window
207 (%glutFullScreen))
208 (error "leaving full-screen not supported")))
209
210(define* (show-window #:optional (window #t))
211 (maybe-with-window window
212 (%glutShowWindow)))
213
214(define* (hide-window #:optional (window #t))
215 (maybe-with-window window
216 (%glutHideWindow)))
217
218(define* (iconify-window #:optional (window #t))
219 (maybe-with-window window
220 (%glutIconifyWindow)))
221
222(define (set-window-title! window str)
223 (assert-top-level-window! (if (eqv? window #t)
224 (current-window)
225 window))
226 (maybe-with-window window
227 (%glutSetWindowTitle str)))
228
229(define (set-window-icon-title! window str)
230 (assert-top-level-window! (if (eqv? window #t)
231 (current-window)
232 window))
233 (maybe-with-window window
234 (%glutSetIconTitle str)))
235
236(define (set-window-cursor! window cursor)
237 (maybe-with-window window
238 (%glutSetCursor cursor)))
239
240(export window?
241 window-id
242 top-level-window?
243 sub-window?
244 window-live?
245 make-window
246 make-sub-window
247 current-window
248 set-current-window
249 destroy-window
250 position-window
251 reshape-window
252 post-redisplay
253 swap-buffers
254 full-screen
255 show-window
256 hide-window
257 iconify-window
258 set-window-title!
259 set-window-icon-title!
260 set-window-cursor!)
261
262(re-export (%glutPopWindow . pop-window)
263 (%glutPushWindow . push-window))
264
265\f
a34227c4
AW
266;;;
267;;; 7 Callback Registration
268;;;
269
270(re-export (%glutDisplayFunc . set-display-callback)
271 (%glutOverlayDisplayFunc . set-overlay-display-callback)
272 (%glutReshapeFunc . set-reshape-callback)
273 (%glutKeyboardFunc . set-keyboard-callback)
274 (%glutMouseFunc . set-mouse-callback)
275 (%glutMotionFunc . set-motion-callback)
276 (%glutPassiveMotionFunc . set-passive-motion-callback)
277 (%glutVisibilityFunc . set-visibility-callback)
278 (%glutEntryFunc . set-entry-callback)
279 (%glutSpecialFunc . set-special-callback)
280 (%glutSpaceballMotionFunc . set-spaceball-motion-callback)
281 (%glutSpaceballRotateFunc . set-spaceball-rotate-callback)
282 (%glutSpaceballButtonFunc . set-spaceball-button-callback)
283 (%glutButtonBoxFunc . set-button-box-callback)
284 (%glutDialsFunc . set-dials-callback)
285 (%glutTabletMotionFunc . set-tablet-motion-callback)
286 (%glutTabletButtonFunc . set-tablet-button-callback)
287 (%glutMenuStatusFunc . set-menu-status-callback)
288 (%glutIdleFunc . set-idle-callback)
289 (%glutTimerFunc . add-timer-callback))
290
291\f
7100c070
DH
292;;;
293;;; 9 State Retrieval
294;;;
295
296;;;
297;;; 9.1 glutGet
298;;;
299
300(define (window-x width)
301 (maybe-with-window window
302 (%glutGet (glut-state window-x))))
303
304(define (window-y width)
305 (maybe-with-window window
306 (%glutGet (glut-state window-y))))
307
308(define (window-position window)
309 (maybe-with-window window
310 (cons (window-x #t)
311 (window-y #t))))
312
313(define (window-width width)
314 (maybe-with-window window
315 (%glutGet (glut-state window-width))))
316
317(define (window-height width)
318 (maybe-with-window window
319 (%glutGet (glut-state window-height))))
320
321(define (window-size window)
322 (maybe-with-window window
323 (cons (window-width #t)
324 (window-height #t))))
325
326(define (window-color-buffer-size window)
327 (maybe-with-window window
328 (%glutGet (glut-state window-buffer-size))))
329
330(define (window-stencil-buffer-size window)
331 (maybe-with-window window
332 (%glutGet (glut-state window-stencil-size))))
333
334(define (window-depth-buffer-size window)
335 (maybe-with-window window
336 (%glutGet (glut-state window-depth-size))))
337
338(define (window-red-size window)
339 (maybe-with-window window
340 (%glutGet (glut-state window-red-size))))
341
342(define (window-green-size window)
343 (maybe-with-window window
344 (%glutGet (glut-state window-green-size))))
345
346(define (window-blue-size window)
347 (maybe-with-window window
348 (%glutGet (glut-state window-blue-size))))
349
350(define (window-alpha-size window)
351 (maybe-with-window window
352 (%glutGet (glut-state window-alpha-size))))
353
354;; TODO: window-accum
355
356(define (window-rgba? window)
357 (maybe-with-window window
358 (eqv? (%glutGet (glut-state window-rgba))
359 1)))
360
361(define (window-double-buffered? window)
362 (maybe-with-window window
363 (eqv? (%glutGet (glut-state window-doublebuffer))
364 1)))
365
366(define (window-parent window)
367 (maybe-with-window window
368 (let ((ret (%glutGet (glut-state window-parent))))
369 (and (not (zero? ret))
370 (%make-window ret #t)))))
371
372(define (window-number-of-children window)
373 (maybe-with-window window
374 (%glutGet (glut-state window-num-children))))
375
376(define (window-colormap-size window)
377 (maybe-with-window window
378 (%glutGet (glut-state window-colormap-size))))
379
380(define (window-number-of-samples window)
381 (maybe-with-window window
382 (%glutGet (glut-state window-num-samples))))
383
384(define (window-stereo? window)
385 (maybe-with-window window
386 (eqv? (%glutGet (glut-state window-stereo))
387 1)))
388
389;; TODO: window-cursor
390
391(export window-x
392 window-y
393 window-position
394 window-width
395 window-height
396 window-size
397 window-color-buffer-size
398 window-stencil-buffer-size
399 window-depth-buffer-size
400 window-red-size
401 window-green-size
402 window-blue-size
403 window-alpha-size
404 window-rgba
405 window-double-buffered?
406 window-parent
407 window-number-of-children
408 window-colormap-size
409 window-number-of-samples
410 window-stereo?)
411
412(define (screen-width)
413 (let ((ret (%glutGet (glut-state screen-width))))
414 (and (not (zero? ret))
415 ret)))
416
417(define (screen-height)
418 (let ((ret (%glutGet (glut-state screen-height))))
419 (and (not (zero? ret))
420 ret)))
421
422(define (screen-size)
423 (and (screen-width)
424 (cons (screen-width)
425 (screen-height))))
426
427(define (screen-width-mm)
428 (let ((ret (%glutGet (glut-state screen-width-mm))))
429 (and (not (zero? ret))
430 ret)))
431
432(define (screen-height-mm)
433 (let ((ret (%glutGet (glut-state screen-height-mm))))
434 (and (not (zero? ret))
435 ret)))
436
437(define (screen-size-mm)
438 (and (screen-width-mm)
439 (cons (screen-width-mm)
440 (screen-height-mm))))
441
442(export screen-width
443 screen-height
444 screen-size
445 screen-width-mm
446 screen-height-mm
447 screen-size-mm)
448
449;; TODO: menu-number-of-items
450
451(define (display-mode-possible?)
452 (eqv? (%glutGet (glut-state display-mode-possible))
453 1))
454
455(define (initial-display-mode)
456 (%glutGet (glut-state init-display-mode)))
457
458(define (initial-window-x)
459 (%glutGet (glut-state init-window-x)))
460
461(define (initial-window-y)
462 (%glutGet (glut-state init-window-y)))
463
464(define (initial-window-position)
465 (cons (initial-window-x)
466 (initial-window-y)))
467
468(define (initial-window-width)
469 (%glutGet (glut-state init-window-width)))
470
471(define (initial-window-height)
472 (%glutGet (glut-state init-window-height)))
473
474(define (initial-window-size)
475 (cons (initial-window-width)
476 (initial-window-height)))
477
478(define (elapsed-time)
479 (%glutGet (glut-state elapsed-time)))
480
481(export display-mode-possible?
482 initial-display-mode
483 initial-window-x
484 initial-window-y
485 initial-window-position
486 initial-window-width
487 initial-window-height
488 initial-window-size
489 elapsed-time)