From 623dd9abca67709a2f354790480cafab1f49f310 Mon Sep 17 00:00:00 2001 From: Alex Charlton Date: Thu, 22 May 2014 19:49:44 -0400 Subject: [PATCH] Reorganize, add callback functions and parameters --- README.md | 125 +++++++++++++++++++---- glfw3-bindings.scm | 14 +++ glfw3.h | 6 +- glfw3.release-info | 1 + glfw3.scm | 244 +++++++++++++++++++++++++++++++++++++++++---- glfw3.setup | 11 +- 6 files changed, 355 insertions(+), 46 deletions(-) create mode 100644 glfw3-bindings.scm diff --git a/README.md b/README.md index e4a0af6..9158ea7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# CHICKEN GLFW3 Bindings +# glfw3 ## Description -Bindings to the [GLFW](http://www.glfw.org/) OpenGL window and event management library, version 3.X. +Bindings to the [GLFW](http://www.glfw.org/) OpenGL window and event management library, version 3.X. Version 3 of GLFW is not backwards compatible with previous major versions of GLFW. ## Installation This repository is a [Chicken Scheme](http://call-cc.org/) egg. @@ -12,42 +12,126 @@ It is part of the [Chicken egg index](http://wiki.call-cc.org/chicken-projects/e * Bind ## Documentation -Direct bindings generated by [bind](http://wiki.call-cc.org/eggref/4/bind). Names Scheme-ified, with GLFW prefixes removed. Constants surrounded by `+`s (e.g. `+alpha-bits+`) +glf3 is separated into two modules: `glfw3-bindingw` and `glfw3`. For almost all purposes, only `glfw3` should be needed. -Version 3 of GLFW is not backwards compatible with previous major versions of GLFW. +`glfw3-bindings` provides direct bindings to GLFW generated by [bind](http://wiki.call-cc.org/eggref/4/bind). Names have been converted from camelCase to hyphenated, with GLFW prefixes removed. Constants are surrounded by `+`s (e.g. `+alpha-bits+`). + +`glfw3` is the high-level interface that should be used in most cases. At the moment it is largely re-exporting `glfw3-bindings`, although many of these functions could still use wrappers (patches welcome!). The not-exactly-the-same-as-the-glfw-api functions are described in the section [High-level interface](#high-level-interface). For information regarding the GLFW API, see the official [GLFW documentation](http://www.glfw.org/documentation.html). + ### High-level interface + [procedure] (init) + +Initializes glfw, as well as `error-callback` and `monitor-callback`. Not needed when using `with-window`. + + [parameter] window + +Contains the window associated with the current context. + + [procedure] (make-context-current WINDOW) + +Performs `glfwMakeContextCurrent` while setting `window`. [procedure] (make-window WIDTH HEIGHT NAME #!key (fullscreen? #f) resizable visible decorated red-bits green-bits blue-bits alpha-bits depth-bits stencil-bits accum-red-bits accum-green-bits accum-blue-bits accum-alpha-bits aux-buffers samples refresh-rate sterio srgb-capable client-api context-version-major context-version-minor context-robustness opengl-forward-compat opengl-debug-context opengl-profile) -Create the window with title string `NAME` and dimensions `WIDTH` by `HEIGHT`. The keys correspond to the available [GLFW window hints](http://www.glfw.org/docs/latest/window.html#window_hints). `resizable`, `visible`, `decorated`, `sterio`, `srgb-capable`, `opengl-forward-compat`, `opengl-debug-context` accept boolean arguments, while all other accept either an integer or an appropriate GLFW constant as per the documentation. +Create a window with title string `NAME` and dimensions `WIDTH` by `HEIGHT`. The keys correspond to the available [GLFW window hints](http://www.glfw.org/docs/latest/window.html#window_hints). `resizable`, `visible`, `decorated`, `sterio`, `srgb-capable`, `opengl-forward-compat`, `opengl-debug-context` accept boolean arguments, while all other accept either an integer or an appropriate GLFW constant as per the documentation. - [parameter] window -Contains the GLFW window object that is created by `make-window`. +Sets the current context to the window that was created. Also sets the swap interval of the window to `1`, for convenience. This can be later set by `swap-interval`. Finally, this initializes all of the window-specific callbacks. [macro] (with-window (WIDTH HEIGHT NAME . KEYS) BODY ...) Initializes GLFW, creates a window as per `make-window`, and runs `BODY` before cleaning up. If [opengl-glew](https://wiki.call-cc.org/eggref/4/opengl-glew) has been included in the same file that this macro is used, opengl-glew will also be initialized. +### Callbacks +`glfw3` provides parameters which contain the functions that are called from GLFW callbacks. The GLFW callbacks are initialized to call these parameters when `init` and `make-window` or `with-window` are used, but they can be changed with the callback setter functions. -## Example -This example must be compiled due to the external function definition. + [parameter] error-callback + +Called when a GLFW error occurs. Expects a function with the signature `(lambda (CODE MESSAGE) ...)`. `CODE` is one of `+not-initialized+`, `+no-current-context+`, `+invalid-enum+`, `+invalid-value+`, `+out-of-memory+`, `+api-unavailable+`, `+version-unavailable+`, `+platform-error+`, `+format-unavailable+`. `MESSAGE` is a string containing an error message. + +Defaults to a function that throws an error and prints `MESSAGE`. + + [parameter] window-position-callback + +Called when a window is moved. Expects a function with the signature `(lambda (WINDOW X Y) ...)`. `WINDOW` is the window that was moved. `X` and `Y` are the coordinates of the upper-left corner of the window. + + [parameter] window-size-callback + +Called when a window is resized. Expects a function with the signature `(lambda (WINDOW W H) ...)`. `WINDOW` is the window that was resized. `W` and `H` are the new dimensions of the window. + + [parameter] window-close-callback + +Called when a window is closed. Expects a function with the signature `(lambda (WINDOW) ...)`. `WINDOW` is the window that was closed. + + [parameter] window-focus-callback + +Called when a window comes into or goes out of focus. Expects a function with the signature `(lambda (WINDOW FOCUSED?) ...)`. `WINDOW` is the affected window, while `FOCUSED?` is true when the window has been focused and false otherwise. + + [parameter] window-iconify-callback +Called when a window is iconified or restored. Expects a function with the signature `(lambda (WINDOW ICONIFIED?) ...)`. `WINDOW` is the affected window, while `ICONIFIED?` is true when the window has been iconified and false otherwise. + + [parameter] framebuffer-size-callback + +Called when a framebuffer is resized. Expects a function with the signature `(lambda (WINDOW W H) ...)`. `WINDOW` is the window whose framebuffer was resized. `W` and `H` are the new dimensions, in pixels, of the framebuffer. + + [parameter] mouse-button-callback + +Called when a mouse button is pressed or released. Expects a function with the signature `(lambda (WINDOW BUTTON ACTION MODS) ...)`. `WINDOW` is the window where the button was pressed, `BUTTON` is the name of the mouse button (one of `+mouse-button-1+` through `+mouse-button-8+`, `+mouse-button-last+`, `+mouse-button-left+`, `+mouse-button-right+`, `+mouse-button-middle+`), `ACTION` is one of `+press+` or `+release+`, and `MODS` is a bit field describing the modifier keys that were held down (any of `+mod-shift+`, `+mod-control+`, `+mod-alt+`, or `+mod-super+`). + + [parameter] cursor-enter-callback + +Called when a cursor enters or leaves a window. Expects a function with the signature `(lambda (WINDOW ENTERED?) ...)`. `WINDOW` is the affected window, and `ENTERED?` is true when the window was entered and false otherwise. + + [parameter] cursor-position-callback + +Called when a cursor moves. Expects a function with the signature `(lambda (WINDOW X Y) ...)`. `WINDOW` is the affected window. `X` and `Y` is the new coordinates of the cursor. + + [parameter] scroll-callback + +Called when a scroll occurs. Expects a function with the signature `(lambda (WINDOW X Y) ...)`. `WINDOW` is the affected window. `X` and `Y` are the scroll offsets. + + [parameter] key-callback + +Called when a key is pressed or released. Expects a function with the signature `(lambda (WINDOW KEY SCANCODE ACTION MODS) ...)`. `WINDOW` is the window where the button was pressed, `KEY` is the name of the key, `SCANCODE` is the system-specific scancode of the key, `ACTION` is one of `+press+`, `+release+` or `+repeat+`, and `MODS` is a bit field describing the modifier keys that were held down (any of `+mod-shift+`, `+mod-control+`, `+mod-alt+`, or `+mod-super+`). + + [parameter] char-callback + +Called when character is entered. Expects a function with the signature `(lambda (WINDOW CHAR) ...)`. `WINDOW` is the affected window, and `CHAR` is the unicode code point of the character. + + [parameter] monitor-callback + +Called when a monitor is connected or disconnected. Expects a function with the signature `(lambda (MONITOR EVENT) ...)`. `MONITOR` is a pointer to the affected monitor, `EVENT` is either `+connected+` or `+disconnected+`. + + [procedure] (set-error-callback! [WINDOW [CALLBACK]]) + [procedure] (set-window-position-callback! [WINDOW [CALLBACK]]) + [procedure] (set-window-size-callback! [WINDOW [CALLBACK]]) + [procedure] (set-window-close-callback! [WINDOW [CALLBACK]]) + [procedure] (set-window-focus-callback! [WINDOW [CALLBACK]]) + [procedure] (set-window-iconify-callback! [WINDOW [CALLBACK]]) + [procedure] (set-framebuffer-size-callback! [WINDOW [CALLBACK]]) + [procedure] (set-mouse-button-callback! [WINDOW [CALLBACK]]) + [procedure] (set-cursor-enter-callback! [WINDOW [CALLBACK]]) + [procedure] (set-cursor-position-callback! [WINDOW [CALLBACK]]) + [procedure] (set-scroll-callback! [WINDOW [CALLBACK]]) + [procedure] (set-key-callback! [WINDOW [CALLBACK]]) + [procedure] (set-char-callback! [WINDOW [CALLBACK]]) + [procedure] (set-monitor-callback! [WINDOW [CALLBACK]]) + +Set the callback functions associated with `WINDOW`. `WINDOW` defaults to `window`. `CALLBACK` defaults to an external function that calls the corresponding callback parameter. + +## Example ``` Scheme -(import foreign) (use (prefix glfw3 glfw:) (prefix opengl-glew gl:)) -(define-external (keyCallback (c-pointer window) - (int key) (int scancode) (int action) (int mods)) - void - (cond - [(and (eq? key glfw:+key-escape+) (eq? action glfw:+press+)) - (glfw:set-window-should-close window 1)])) +(glfw:key-callback (lambda (window key scancode action mods) + (cond + [(and (eq? key glfw:+key-escape+) (eq? action glfw:+press+)) + (glfw:set-window-should-close window #t)]))) (glfw:with-window (640 480 "Example" resizable: #f) - (glfw:set-key-callback (glfw:window) #$keyCallback) (let loop () (glfw:swap-buffers (glfw:window)) (glfw:poll-events) @@ -56,6 +140,13 @@ This example must be compiled due to the external function definition. ``` ## Version history +### Version 0.4.0 +* Reorganize into two modules +* Add callback functions and parameters +* Add `init` +* Add `make-context-current` +* Fix a number of unsafe bindings that could potentially call back to Scheme + ### Version 0.3.0 * Make `*window*` a parameter named `window` diff --git a/glfw3-bindings.scm b/glfw3-bindings.scm new file mode 100644 index 0000000..434cdcd --- /dev/null +++ b/glfw3-bindings.scm @@ -0,0 +1,14 @@ +(module glfw3-bindings * + +(import chicken scheme foreign) +(use bind) + +(bind-rename/pattern "^GLFW_([A-Z].+)$" "+\\1+") +(bind-rename/pattern "(.*)GLFW(.+)$" "\\1\\2") +(bind-rename/pattern "glfw(.+)$" "\\1") +(bind-options default-renaming: "" + export-constants: #t) + +(bind-file* "glfw3.h") + +) ; end glfw3-bindings diff --git a/glfw3.h b/glfw3.h index 81939eb..d444641 100644 --- a/glfw3.h +++ b/glfw3.h @@ -691,7 +691,7 @@ typedef struct GLFWgammaramp * * @ingroup init */ -bool glfwInit(void); +___safe bool glfwInit(void); /*! @brief Terminates the GLFW library. * @@ -1060,7 +1060,7 @@ void glfwWindowHint(int target, int hint); * * @ingroup window */ -GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share); +___safe GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share); /*! @brief Destroys the specified window and its context. * @@ -2016,7 +2016,7 @@ void glfwSwapBuffers(GLFWwindow* window); * * @ingroup context */ -void glfwSwapInterval(int interval); +___safe void glfwSwapInterval(int interval); /*! @brief Returns whether the specified extension is available. * diff --git a/glfw3.release-info b/glfw3.release-info index 088efc3..7018eb2 100644 --- a/glfw3.release-info +++ b/glfw3.release-info @@ -1,5 +1,6 @@ (repo git "git://github.com/AlexCharlton/{egg-name}-chicken.git") (uri targz "https://codeload.github.com/AlexCharlton/{egg-name}-chicken/tar.gz/{egg-release}") +(release "0.4.0") (release "0.3.0") (release "0.2.0") (release "0.1.0") \ No newline at end of file diff --git a/glfw3.scm b/glfw3.scm index fbb6137..b10d594 100644 --- a/glfw3.scm +++ b/glfw3.scm @@ -1,19 +1,206 @@ -(module glfw3 * +(module glfw3 (make-window + with-window + window + make-context-current + init + error-callback + window-position-callback + window-size-callback + window-close-callback + window-focus-callback + window-iconify-callback + framebuffer-size-callback + mouse-button-callback + cursor-enter-callback + cursor-position-callback + scroll-callback + key-callback + char-callback + monitor-callback + set-error-callback! + set-window-position-callback! + set-window-size-callback! + set-window-close-callback! + set-window-focus-callback! + set-window-iconify-callback! + set-framebuffer-size-callback! + set-mouse-button-callback! + set-cursor-enter-callback! + set-cursor-position-callback! + set-scroll-callback! + set-key-callback! + set-char-callback! + set-monitor-callback!) (import chicken scheme foreign) +(use data-structures (prefix glfw3-bindings %)) -(use bind data-structures) +(reexport (except glfw3-bindings + init + make-context-current + set-error-callback + set-window-pos-callback + set-window-size-callback + set-window-close-callback + set-window-focus-callback + set-window-iconify-callback + set-framebuffer-size-callback + set-mouse-button-callback + set-cursor-enter-callback + set-cursor-pos-callback + set-scroll-callback + set-key-callback + set-char-callback + set-monitor-callback)) -(bind-rename/pattern "^GLFW_([A-Z].+)$" "+\\1+") -(bind-rename/pattern "(.*)GLFW(.+)$" "\\1\\2") -(bind-rename/pattern "glfw(.+)$" "\\1") -(bind-options default-renaming: "" - export-constants: #t) +;;; Callbacks +(define error-callback (make-parameter (lambda (code err) + (error 'glfw3 err)))) +(define window-position-callback (make-parameter (lambda (window x y) #f))) +(define window-size-callback (make-parameter (lambda (window w h) #f))) +(define window-close-callback (make-parameter (lambda (window) #f))) +(define window-refresh-callback (make-parameter (lambda (window) #f))) +(define window-focus-callback (make-parameter (lambda (window focused?) #f))) +(define window-iconify-callback (make-parameter (lambda (window iconified?) #f))) +(define framebuffer-size-callback (make-parameter (lambda (window w h) #f))) +(define mouse-button-callback (make-parameter (lambda (window button action mods) #f))) +(define cursor-position-callback (make-parameter (lambda (window x y) #f))) +(define cursor-enter-callback (make-parameter (lambda (window entered?) #f))) +(define scroll-callback (make-parameter (lambda (window x y) #f))) +(define key-callback (make-parameter (lambda (window key scancode action mods) #f))) +(define char-callback (make-parameter (lambda (window char) #f))) +(define monitor-callback (make-parameter (lambda (monitor event) #f))) -(bind-file* "glfw3.h") +(define-external (glfw3ErrorCallback (int code) (c-string err)) + void + ((error-callback) code err)) + +(define-external (glfw3WindowPositionCallback (c-pointer window) (int x) (int y)) + void + ((window-position-callback) window x y)) + +(define-external (glfw3WindowSizeCallback (c-pointer window) (int w) (int h)) + void + ((window-size-callback) window w h)) + +(define-external (glfw3WindowCloseCallback (c-pointer window)) + void + ((window-close-callback) window)) + +(define-external (glfw3WindowRefreshCallback (c-pointer window)) + void + ((window-refresh-callback) window)) + +(define-external (glfw3WindowFocusCallback (c-pointer window) (bool focused?)) + void + ((window-focus-callback) window focused?)) + +(define-external (glfw3WindowIconifyCallback (c-pointer window) (bool iconified?)) + void + ((window-iconify-callback) window iconified?)) + +(define-external (glfw3FramebufferSizeCallback (c-pointer window) (int w) (int h)) + void + ((framebuffer-size-callback) window w h)) + +(define-external (glfw3MouseButtonCallback (c-pointer window) (int button) + (int action) (int mods)) + void + ((mouse-button-callback) window button action mods)) + +(define-external (glfw3CursorPositionCallback (c-pointer window) + (double x) (double y)) + void + ((cursor-position-callback) window x y)) + +(define-external (glfw3CursorEnterCallback (c-pointer window) (bool entered?)) + void + ((cursor-enter-callback) window entered?)) + +(define-external (glfw3ScrollCallback (c-pointer window) + (double x) (double y)) + void + ((scroll-callback) window x y)) + +(define-external (glfw3KeyCallback (c-pointer window) (int key) (int scancode) + (int action) (int mods)) + void + ((key-callback) window key scancode action mods)) + +(define-external (glfw3CharCallback (c-pointer window) (unsigned-int char)) + void + ((char-callback) window char)) + +(define-external (glfw3MonitorCallback (c-pointer window) (int event)) + void + ((monitor-callback) window event)) + +(define (set-error-callback! #!optional callback) + (%set-error-callback (or callback #$glfw3ErrorCallback))) + +(define (set-monitor-callback! #!optional callback) + (%set-monitor-callback (or callback #$glfw3MonitorCallback))) + +(define (set-window-position-callback! #!optional win callback) + (%set-window-pos-callback (or win (window)) + (or callback #$glfw3WindowPositionCallback))) + +(define (set-window-size-callback! #!optional win callback) + (%set-window-size-callback (or win (window)) + (or callback #$glfw3WindowSizeCallback))) + +(define (set-window-close-callback! #!optional win callback) + (%set-window-close-callback (or win (window)) + (or callback #$glfw3WindowCloseCallback))) + +(define (set-window-focus-callback! #!optional win callback) + (%set-window-focus-callback (or win (window)) + (or callback #$glfw3WindowFocusCallback))) + +(define (set-window-iconify-callback! #!optional win callback) + (%set-window-iconify-callback (or win (window)) + (or callback #$glfw3WindowIconifyCallback))) + +(define (set-framebuffer-size-callback! #!optional win callback) + (%set-framebuffer-size-callback (or win (window)) + (or callback #$glfw3FramebufferSizeCallback))) + +(define (set-mouse-button-callback! #!optional win callback) + (%set-mouse-button-callback (or win (window)) + (or callback #$glfw3MouseButtonCallback))) + +(define (set-cursor-enter-callback! #!optional win callback) + (%set-cursor-enter-callback (or win (window)) + (or callback #$glfw3CursorEnterCallback))) + +(define (set-cursor-position-callback! #!optional win callback) + (%set-cursor-pos-callback (or win (window)) + (or callback #$glfw3CursorPositionCallback))) + +(define (set-scroll-callback! #!optional win callback) + (%set-scroll-callback (or win (window)) + (or callback #$glfw3ScrollCallback))) + +(define (set-key-callback! #!optional win callback) + (%set-key-callback (or win (window)) + (or callback #$glfw3KeyCallback))) + +(define (set-char-callback! #!optional win callback) + (%set-char-callback (or win (window)) + (or callback #$glfw3CharCallback))) + + +;;; Initialization and window creation +(define (init) + (set-error-callback!) + (%init)) (define window (make-parameter #f)) +(define (make-context-current win) + (window win) + (%make-context-current win)) + (define (make-window w h name #!rest hints #!key [fullscreen? #f]) (define *hints* `((resizable: ,+resizable+ bool:) @@ -36,24 +223,37 @@ (opengl-forward-compat: ,+opengl-forward-compat+ bool:) (opengl-debug-context: ,+opengl-debug-context+ bool:) (opengl-profile: ,+opengl-any-profile+))) - (default-window-hints) + (%default-window-hints) (let loop ([hints hints]) (when (>= (length hints) 2) (let* ([key (car hints)] [val (cadr hints)] [hint (alist-ref key *hints*)]) (when hint - (window-hint (car hint) (if (and (= (length hint) 2) - (eq? (cadr hint) bool:)) - (if val 1 0) - val)))) + (%window-hint (car hint) (if (and (= (length hint) 2) + (eq? (cadr hint) bool:)) + (if val 1 0) + val)))) (loop (cddr hints)))) - (window (create-window w h name - (if fullscreen? - (get-primary-monitor) - #f) - #f)) - (make-context-current (window)) + (make-context-current (%create-window w h name + (if fullscreen? + (get-primary-monitor) + #f) + #f)) + (%swap-interval 1) + (set-monitor-callback!) + (set-window-position-callback!) + (set-window-size-callback!) + (set-window-close-callback!) + (set-window-focus-callback!) + (set-window-iconify-callback!) + (set-framebuffer-size-callback!) + (set-mouse-button-callback!) + (set-cursor-enter-callback!) + (set-cursor-position-callback!) + (set-scroll-callback!) + (set-key-callback!) + (set-char-callback!) (window)) (define-syntax with-window @@ -65,7 +265,7 @@ (when (feature? #:opengl-glew) (opengl-glew#init)) body ... - (destroy-window (window)) - (terminate))])) + (%destroy-window (window)) + (%terminate))])) -) ; end module +) ; end glfw3 diff --git a/glfw3.setup b/glfw3.setup index d6d6bba..71405fb 100644 --- a/glfw3.setup +++ b/glfw3.setup @@ -1,11 +1,14 @@ ;; glfw3.setup -*- scheme -*- (if (feature? unix:) - (compile -d0 -O2 -J -s -l:libglfw.so.3 glfw3.scm) - (compile -d0 -O2 -J -s -lglfw glfw3.scm)) + (compile -d0 -O2 -J -s -l:libglfw.so.3 glfw3-bindings.scm) + (compile -d0 -O2 -J -s -lglfw glfw3-bindings.scm)) +(compile -d0 -O2 -s glfw3-bindings.import.scm) + +(compile -d0 -O2 -J -s glfw3.scm) (compile -d0 -O2 -s glfw3.import.scm) (install-extension 'glfw3 - '("glfw3.so" "glfw3.import.so") - '((version "0.3.0"))) + '("glfw3.so" "glfw3.import.so" "glfw3-bindings.so" "glfw3-bindings.import.so") + '((version "0.4.0")))