Skip to content

Shirakumo/framebuffers

Repository files navigation

# About Framebuffers
This library implements direct access to underlying operating system framebuffer mechanisms, including input handling. With it you can create native windows on Windows (win32), Linux (x11/wayland), Mac (Cocoa), and Mezzano, all without relying on external C libraries.

## How To
A trivial example is as follows, assuming ``org.shirakumo.framebuffers`` is locally nicknamed to ``fb``:

:: common lisp
(fb:with-window (w :size '(800 . 600)))
::

This will open a window and start its event loop. When the user requests a close, it'll automatically close it and clean it back up again.

To watch what events are going on, we can add a catchall handler:

:: common lisp
(fb:with-window (w :size '(800 . 600))
  (T (type &rest args)
    (print (list* type args))))
::

However, this being a framebuffer library, you're likely most interested in how to actually push pixels to the screen. Let's fill the window with a repeating gradient:

:: common lisp
(fb:with-window (w :size '(800 . 600))
  (fb:window-refreshed ()
    (fb:do-pixels (buf i x y) w
      (setf (aref buf (+ 0 i)) (mod x 256))
      (setf (aref buf (+ 1 i)) (mod y 256))
      (setf (aref buf (+ 2 i)) 0)
      (setf (aref buf (+ 3 i)) 255))
    (fb:swap-buffers w)))
::

``do-pixels`` simply iterates over the pixels in the backing ``buffer``, using an BGRA layout. You can use whatever method you like to fill the buffer with pixel data, and call ``swap-buffers`` to display it.

The API also exposes various functions to manage the window properties and let you handle events that occur. Please refer to the documentation of ``window`` and ``event-handler`` for a listing of each.

## Controlling the Event Loop
The previously used ``with-window`` macro uses a dynamically established event handler to let you conveniently create an event loop. However, for larger projects you'll usually want a more decentralised code structure, in which case you'll instead want to manually manage the loop and how events are handled. To do so, you'll first want to define your own ``event-handler`` class, and methods for the events you care about:

:: common lisp
(defclass event-handler (fb:event-handler) ())

(defmethod fb:key-changed ((handler event-handler) key scan-code modifiers)
  (print key))
::

Then when you create your window using ``open``, pass an instance of your event handler as an initarg.

:: common lisp
(fb:open :event-handler (make-instance 'event-handler))
::

Alternatively you can set it later using the ``event-handler`` accessor. The ``window`` object returned by ``open`` is specific to the type of backend used, which is why you must use an ``event-handler`` subclass to specialise methods on, instead.

In order to retrieve the associated ``window`` for the handler within a callback method, simply use the ``window`` accessor function.

Once you have your window instance, you must periodically call ``process-events`` on it in order to handle whatever has been queued for it. ``process-events`` also has a couple of options to more efficiently wait for events in a loop.

## Supported Backends
Currently this library supports the following backends:

; - Cocoa
- Mezzano
; - Wayland
- Win32
- X11