Common Lisp SDL2 Tutorial

  • Tutorial
SDL2 is a great library, but there are not many tutorials on it.
Common Lisp is a great language, but articles on it are disastrously few.
I think this is enough to write this series of articles.

Why did I choose a common bed? Well, the taste and color as they say.
However, there are reasons:



In fact, this series is an adaptation of tutorials from Lazy Foo:
lazyfoo.net/tutorials/SDL/index.php

In this article I will not explain in detail how to install all the necessary software, but
if this is really interesting for someone, please write about it
in comments.

To install SDL2, use the tips of Fu: lazyfoo.net/tutorials/SDL/01_hello_SDL/index.php .

As for Lisp, I use the implementation of www.sbcl.org and www.quicklisp.org .
At the moment, performance was tested only in it.

Next, I use the cl-sdl2 library: github.com/lispgames/cl-sdl2 .
It just so happened that support for some functionality from SDL2, for example
surfaces, is not fully implemented in it. But this does not matter, I will add the
necessary functionality as I move through the tutorials. Therefore, do
not install the version from quicklisp, but immediately clone the master branch into ~/quicklisp/local-projects.

It is assumed that you have a minimal understanding of the lisp syntax and are not afraid of the abundance of brackets.
As the main means of interacting with Lisp environments, I will use slime.
Have you tried spacemacs yet ? Then we go to you!

Those who don’t need lyrics, but need code: github.com/TatriX/cl-sdl2-tutorial

White screen of life


To begin with, just make SDL2 show us a white-filled window.

Obviously, we need the cl-sdl2 library itself. Connect it:
CL-USER> (ql:quickload :sdl2)

We will not complicate our task and create a window of a fixed size.
To do this, we will declare global (and even more special ) variables for the width and height of our window, because magic numbers are evil.
(defparameter *screen-width* 640)
(defparameter *screen-height* 480)

Now create a function that will open a window for us, fill
it with white, wait a while, and close it.

We simply call our main function and add an optional
named parameter to it, so that we can adjust the time after which the
window closes. By default, two seconds is behind our eyes.
(defun main (&key (delay 2000))

Then we need to initialize sdl2, telling the library which
subsystem we want to use. For this, cl-sdl2 provides us with a convenient macro:
  (sdl2:with-init (:video)

We want to use only the graphics output subsystem, therefore
we will pass the symbol: video. You ask: “how should I have guessed
what to transmit exactly: video?” We answer: cl-sdl2 converts
SDL_ constants to the corresponding characters. For example,
we can open the documentation using the SDL_Init method and see the
available flags: wiki.libsdl.org/SDL_Init#Remarks
To get the required character, cut off the name of the constant SDL_INIT_ and
convert the flag to lowercase.

The beauty of with macros is that they necessarily
free all allocated resources, freeing us from the need
to monitor this on our own.

Ok, next we will create a window:
 (sdl2:with-window (window :title "SDL2 Window" :w *screen-width* :h *screen-height*)

This is another with macro. This time, the first element of the
macro argument list will be the window symbol, through which
we will refer to the created window in the macro body . The named
parameters: title,: w,: h I think are quite obvious and need no
explanation.

Everything is clear with the window, but now we want to fill the resulting window with white
. One of the options for implementing the plan will be the use of
"surfaces", they are surfaces. In fact, a surface is a structure
containing pixels of a certain area used in software
rendering. For example, we can get the surface of our window:
      (let ((screen-surface (sdl2:get-window-surface window)))

and fill it with white:
        (sdl2:fill-rect screen-surface
                        nil
                        (sdl2:map-rgb (sdl2:surface-format screen-surface) 255 255 255))

The first argument is the rectangle we want to fill. If it is not
transmitted, we will fill the entire area. Why miserable #fff
write in such a complicated way? It's all about a variety of
pixel formats , screens, and the like. And since the SDL2 library is
cross-platform,
various functions are used to apply all the necessary transformations , such as map-rgb in this case.

Fill the window flooded, but this is not enough. Now we need to politely ask the library to update our window:
        (sdl2:update-window window)

Considering that the whole described process takes so long in a split second,
but we still want to enjoy the result, we ask sdl to wait a bit:
(sdl2: delay delay)
Well and most important:
)))


That's all. It remains to run our creation, and they hope that we will not crash into the debugger:
CL-USER> (main)




Just in case,
full source
(defparameter *screen-width* 640)
(defparameter *screen-height* 480)
(defun main (&key (delay 2000))
  (sdl2:with-init (:video)
    (sdl2:with-window (window :title "SDL2 Window" :w *screen-width* :h *screen-height*)
      (let ((screen-surface (sdl2:get-window-surface window)))
        (sdl2:fill-rect screen-surface
                        nil
                        (sdl2:map-rgb (sdl2:surface-format screen-surface) 255 255 255))
        (sdl2:update-window window)
        (sdl2:delay delay)))))



Honestly, I was planning in one article to tell immediately about the first three tutorials, but somehow already a lot of text came out.

For the impatient, once again, a link to the tutorial code (at the time of writing of the article 16 pieces):
github.com/TatriX/cl-sdl2-tutorial

I hope this was interesting and informative.

Only registered users can participate in the survey. Please come in.

Do I need more lisp on the Habr?

  • 78.2% Of course you need! 140
  • 13.4% Take your brackets to where you dug them 24
  • 8.3% Who is here? fifteen

Also popular now: