Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
134 lines (104 sloc) 5.65 KB

Introduction into cl-bodge graphics system

This step-by-step guide will introduce you to cl-bodge graphics API provided by cl-bodge/graphics system starting with core concepts first and introducing more complex notions later.

cl-bodge/graphics overview

In Common Lisp, function format allows you to print formatted strings into character streams: it renders template string into an output by filling control placeholders with supplied arguments. cl-bodge adapts this concept for graphics with function render:

(defun render (output pipeline &rest input &key &allow-other-keys)
  ...)

Signature looks familiar, isn’t it? Indeed, it resembles format one except input arguments are keyword pairs. It works quite similar too!

output argument is often the target framebuffer for the rendering we want to perform into. If you pass t as output rendering will be performed into default framebuffer just like format would render string into standard output. But you also can provide texture as a target! All the machinery required to render directly into texture cl-bodge will handle for you.

pipeline is an object representing rendering operation and input is a list of key-value pairs to control pipeline behavior.

Now, output is a framebuffer or a texture, but what is pipeline then? It can be various things, but cl-bodge/graphics system exposes only one: shader pipeline.

Shader pipelines are defined with defpipeline macro and assembled from shaders using make-shader-pipeline function. Unlike various CL graphics libraries (e.g. CEPL) cl-bodge shaders are written directly in GLSL. But fear not, live reload of GLSL sources is supported (we will discuss related configuration later), so you can play with shader output in live session. Shaders are defined with defshader macro.

Summing up, to display something via cl-bodge\graphics:

  1. Define shaders
  2. Define a pipeline
  3. Make a pipeline object
  4. Optionally, make a framebuffer
  5. Pass a framebuffer, a pipeline and pipeline arguments to render function

Guide How-To

This guide is written in literate programming style - documentation is your code. You can evaluate provided examples block-by-block in your Common Lisp REPL of choice, or use org-mode to do the same in a more convenient fasion or execute all code blocks in a buffer at once, or, ultimately, you can just load any system described below in ASDF definitions section and call appropriate run-example functions.

Preparations

Just right before digging deeper into cl-bodge, lets make little preparations by loading required dependencies and defining a few of helper functions that will help us in our future adventures.

(ql:quickload '(bodge-appkit cl-bodge/graphics))
(cl:defpackage :hello-bodge-graphics
  (:use :cl :cl-bodge.engine :cl-bodge.graphics)
  (:export #:*project-path*
           #:merge-project-path))
(cl:in-package :hello-bodge-graphics)

(defparameter *project-path* nil)

(defun merge-project-path (relative-path)
  "Construct a full path joining *project-path* or a system-relative-pathname if *project-path*
is nil with provided relative path"
  (merge-pathnames relative-path (or *project-path*
                                     (asdf:system-relative-pathname :hello-bodge-graphics "./"))))

If you are evaluating from org-mode, this block will setup correct project path

(setf hello-bodge-graphics:*project-path* (uiop:pathname-directory-pathname %buffer-file-name%))

If you are evaluating in REPL, please set *project-path* manually:

(setf hello-bodge-graphics:*project-path* "/full/path/to/project/")

Now we are ready to explore the examples! Also check out Configure Emacs for cl-bodge guide to configure live-reloading of shaders directly from glsl-mode buffer.

Examples

Minimal Example
Only absolutely essential code to bring something up onto screen

ASDF definitions

Lets arrange ASDF definitions for all of our examples we provided above to load them anytime later instead of manually evaluating code blocks one-by-one.

(asdf:defsystem :hello-bodge-graphics
  :description "Guide to graphics subsystem of cl-bodge"
  :version "1.0.0"
  :author "Pavel Korolev"
  :license "MIT"
  :mailto "dev@borodust.org"
  :depends-on (cl-bodge/graphics bodge-appkit)
  :pathname "src"
  :serial t
  :components ((:file "hello-bodge-graphics")))

(asdf:defsystem :hello-bodge-graphics/pass-through
  :description "Pass-through pipeline example for cl-bodge/graphics"
  :version "1.0.0"
  :author "Pavel Korolev"
  :license "MIT"
  :mailto "dev@borodust.org"
  :depends-on (hello-bodge-graphics)
  :pathname "src/pass-through/"
  :serial t
  :components ((:file "app")))