pass pairs to set-initial-window-{position,size}
[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
114(define-record-type window
115 (%%make-window id live?)
116 window?
117 (id window-id)
118 (live? window-live? set-window-live?!))
119
120(define (assert-live-window! window)
121 (unless (window-live? window)
122 (error "window already destroyed" window)))
123
124(define (top-level-window? window)
125 (not (window-parent window)))
126
127(define (sub-window? window)
128 (and (window-parent window)
129 #t))
130
131(define (assert-top-level-window! window)
132 (unless (top-level-window? window)
133 (error "not a top-level window" window)))
134
135;; Memoized so state requests can return the same object.
136(define %make-window (memoize %%make-window))
137
138(define (make-window str)
139 (let ((id (%glutCreateWindow str)))
140 (%make-window id #t)))
141
142(define (make-sub-window window x y width height)
143 (let ((id (%glutCreateSubWindow (window-id window) x y width height)))
144 (%make-window id #t)))
145
146(define (current-window)
147 (let ((ret (%glutGetWindow)))
148 (and (not (zero? ret))
149 (%make-window ret #t))))
150
151(define (set-current-window window)
152 (assert-live-window! window)
153 (let ((old (current-window)))
154 (%glutSetWindow (window-id window))
155 old))
156
157(define (destroy-window window)
158 (set-window-live?! window #f)
159 ;; TODO: Also mark sub-windows.
160 (%glutDestroyWindow (window-id window)))
161
162;; A short detour for some syntax forms, then most window procedures
163;; operate on /either/ current-window or a specified window.
164
165(define (with-window* window thunk)
166 (let* ((swap-windows (lambda ()
167 (set! window (set-current-window window)))))
168 (dynamic-wind swap-windows thunk swap-windows)))
169
170;; emacs: (put 'with-window 'scheme-indent-function 1)
171(define-syntax with-window
172 (syntax-rules ()
173 ((_ window body1 body2 ...)
174 (with-window* window (lambda () body1 body2 ...)))))
175
176;; emacs: (put 'maybe-with-window 'scheme-indent-function 1)
177(define-syntax maybe-with-window
178 (syntax-rules ()
179 ((_ window body1 body2 ...)
180 (if (eqv? window #t) ; use current-window
181 (begin
182 body1 body2 ...)
183 (with-window window
184 (assert-live-window! window)
185 body1 body2 ...)))))
186
187(export with-window*)
188
189(export-syntax with-window)
190
191;; TODO: These post requests, and do not update the window parameters
192;; immediately. Otherwise, names like set-window-position! may be
193;; more appropriate on the Scheme side.
194
195(define (position-window window x y)
196 (maybe-with-window window
197 (%glutPositionWindow x y)))
198
199(define (reshape-window window width height)
200 (maybe-with-window window
201 (%glutReshapeWindow width height)))
202
203(define* (post-redisplay #:optional (window #t))
204 (maybe-with-window window
205 (%glutPostRedisplay)))
206
207(define* (swap-buffers #:optional (window #t))
208 (maybe-with-window window
209 (%glutSwapBuffers)))
210
211(define (full-screen window full-screen?)
212 (if full-screen?
213 (maybe-with-window window
214 (%glutFullScreen))
215 (error "leaving full-screen not supported")))
216
217(define* (show-window #:optional (window #t))
218 (maybe-with-window window
219 (%glutShowWindow)))
220
221(define* (hide-window #:optional (window #t))
222 (maybe-with-window window
223 (%glutHideWindow)))
224
225(define* (iconify-window #:optional (window #t))
226 (maybe-with-window window
227 (%glutIconifyWindow)))
228
229(define (set-window-title! window str)
230 (assert-top-level-window! (if (eqv? window #t)
231 (current-window)
232 window))
233 (maybe-with-window window
234 (%glutSetWindowTitle str)))
235
236(define (set-window-icon-title! window str)
237 (assert-top-level-window! (if (eqv? window #t)
238 (current-window)
239 window))
240 (maybe-with-window window
241 (%glutSetIconTitle str)))
242
243(define (set-window-cursor! window cursor)
244 (maybe-with-window window
245 (%glutSetCursor cursor)))
246
247(export window?
248 window-id
249 top-level-window?
250 sub-window?
251 window-live?
252 make-window
253 make-sub-window
254 current-window
255 set-current-window
256 destroy-window
257 position-window
258 reshape-window
259 post-redisplay
260 swap-buffers
261 full-screen
262 show-window
263 hide-window
264 iconify-window
265 set-window-title!
266 set-window-icon-title!
267 set-window-cursor!)
268
269(re-export (%glutPopWindow . pop-window)
270 (%glutPushWindow . push-window))
271
272\f
a34227c4
AW
273;;;
274;;; 7 Callback Registration
275;;;
276
277(re-export (%glutDisplayFunc . set-display-callback)
278 (%glutOverlayDisplayFunc . set-overlay-display-callback)
279 (%glutReshapeFunc . set-reshape-callback)
280 (%glutKeyboardFunc . set-keyboard-callback)
281 (%glutMouseFunc . set-mouse-callback)
282 (%glutMotionFunc . set-motion-callback)
283 (%glutPassiveMotionFunc . set-passive-motion-callback)
284 (%glutVisibilityFunc . set-visibility-callback)
285 (%glutEntryFunc . set-entry-callback)
286 (%glutSpecialFunc . set-special-callback)
287 (%glutSpaceballMotionFunc . set-spaceball-motion-callback)
288 (%glutSpaceballRotateFunc . set-spaceball-rotate-callback)
289 (%glutSpaceballButtonFunc . set-spaceball-button-callback)
290 (%glutButtonBoxFunc . set-button-box-callback)
291 (%glutDialsFunc . set-dials-callback)
292 (%glutTabletMotionFunc . set-tablet-motion-callback)
293 (%glutTabletButtonFunc . set-tablet-button-callback)
294 (%glutMenuStatusFunc . set-menu-status-callback)
94b789ae 295 (%glutIdleFunc . set-idle-callback))
a34227c4
AW
296
297\f
7100c070
DH
298;;;
299;;; 9 State Retrieval
300;;;
301
302;;;
303;;; 9.1 glutGet
304;;;
305
306(define (window-x width)
307 (maybe-with-window window
308 (%glutGet (glut-state window-x))))
309
310(define (window-y width)
311 (maybe-with-window window
312 (%glutGet (glut-state window-y))))
313
314(define (window-position window)
315 (maybe-with-window window
316 (cons (window-x #t)
317 (window-y #t))))
318
319(define (window-width width)
320 (maybe-with-window window
321 (%glutGet (glut-state window-width))))
322
323(define (window-height width)
324 (maybe-with-window window
325 (%glutGet (glut-state window-height))))
326
327(define (window-size window)
328 (maybe-with-window window
329 (cons (window-width #t)
330 (window-height #t))))
331
332(define (window-color-buffer-size window)
333 (maybe-with-window window
334 (%glutGet (glut-state window-buffer-size))))
335
336(define (window-stencil-buffer-size window)
337 (maybe-with-window window
338 (%glutGet (glut-state window-stencil-size))))
339
340(define (window-depth-buffer-size window)
341 (maybe-with-window window
342 (%glutGet (glut-state window-depth-size))))
343
344(define (window-red-size window)
345 (maybe-with-window window
346 (%glutGet (glut-state window-red-size))))
347
348(define (window-green-size window)
349 (maybe-with-window window
350 (%glutGet (glut-state window-green-size))))
351
352(define (window-blue-size window)
353 (maybe-with-window window
354 (%glutGet (glut-state window-blue-size))))
355
356(define (window-alpha-size window)
357 (maybe-with-window window
358 (%glutGet (glut-state window-alpha-size))))
359
360;; TODO: window-accum
361
362(define (window-rgba? window)
363 (maybe-with-window window
364 (eqv? (%glutGet (glut-state window-rgba))
365 1)))
366
367(define (window-double-buffered? window)
368 (maybe-with-window window
369 (eqv? (%glutGet (glut-state window-doublebuffer))
370 1)))
371
372(define (window-parent window)
373 (maybe-with-window window
374 (let ((ret (%glutGet (glut-state window-parent))))
375 (and (not (zero? ret))
376 (%make-window ret #t)))))
377
378(define (window-number-of-children window)
379 (maybe-with-window window
380 (%glutGet (glut-state window-num-children))))
381
382(define (window-colormap-size window)
383 (maybe-with-window window
384 (%glutGet (glut-state window-colormap-size))))
385
386(define (window-number-of-samples window)
387 (maybe-with-window window
388 (%glutGet (glut-state window-num-samples))))
389
390(define (window-stereo? window)
391 (maybe-with-window window
392 (eqv? (%glutGet (glut-state window-stereo))
393 1)))
394
395;; TODO: window-cursor
396
397(export window-x
398 window-y
399 window-position
400 window-width
401 window-height
402 window-size
403 window-color-buffer-size
404 window-stencil-buffer-size
405 window-depth-buffer-size
406 window-red-size
407 window-green-size
408 window-blue-size
409 window-alpha-size
410 window-rgba
411 window-double-buffered?
412 window-parent
413 window-number-of-children
414 window-colormap-size
415 window-number-of-samples
416 window-stereo?)
417
418(define (screen-width)
419 (let ((ret (%glutGet (glut-state screen-width))))
420 (and (not (zero? ret))
421 ret)))
422
423(define (screen-height)
424 (let ((ret (%glutGet (glut-state screen-height))))
425 (and (not (zero? ret))
426 ret)))
427
428(define (screen-size)
429 (and (screen-width)
430 (cons (screen-width)
431 (screen-height))))
432
433(define (screen-width-mm)
434 (let ((ret (%glutGet (glut-state screen-width-mm))))
435 (and (not (zero? ret))
436 ret)))
437
438(define (screen-height-mm)
439 (let ((ret (%glutGet (glut-state screen-height-mm))))
440 (and (not (zero? ret))
441 ret)))
442
443(define (screen-size-mm)
444 (and (screen-width-mm)
445 (cons (screen-width-mm)
446 (screen-height-mm))))
447
448(export screen-width
449 screen-height
450 screen-size
451 screen-width-mm
452 screen-height-mm
453 screen-size-mm)
454
455;; TODO: menu-number-of-items
456
457(define (display-mode-possible?)
458 (eqv? (%glutGet (glut-state display-mode-possible))
459 1))
460
461(define (initial-display-mode)
462 (%glutGet (glut-state init-display-mode)))
463
464(define (initial-window-x)
465 (%glutGet (glut-state init-window-x)))
466
467(define (initial-window-y)
468 (%glutGet (glut-state init-window-y)))
469
470(define (initial-window-position)
471 (cons (initial-window-x)
472 (initial-window-y)))
473
474(define (initial-window-width)
475 (%glutGet (glut-state init-window-width)))
476
477(define (initial-window-height)
478 (%glutGet (glut-state init-window-height)))
479
480(define (initial-window-size)
481 (cons (initial-window-width)
482 (initial-window-height)))
483
484(define (elapsed-time)
485 (%glutGet (glut-state elapsed-time)))
486
487(export display-mode-possible?
488 initial-display-mode
489 initial-window-x
490 initial-window-y
491 initial-window-position
492 initial-window-width
493 initial-window-height
494 initial-window-size
495 elapsed-time)