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