Cautionary Tales: Incompatible ECL SFFI SDL2 C/C++ LISP


Cautionary Tales Incomptable ECL SDL2 C lisp.

Opens a blank window, which reads keypresses and modifier keys until closed (escape or a normal way of quitting quits)

1. (Don't) Use It Like This:

In this file, C-c C-v t to generate keys.c.ecl.lisp, then (eg)

$ doas pkg_add sdl2 ecl
$ ecl
> (ext:install-c-compiler)
> (setf c:*user-ld-flags* "-lSDL2")
> (compile-file "keys.ecl.lisp" :load t)
> (sdl2-receive-keys) ; pops up a window. Use Esc or your wm to quit
((:|Left Alt| (:LCTRL :LALT :NUM) 1073742050 4416)
 (:A (:LCTRL :LALT :NUM) 97 4416)
 (:|Right Shift| (:RSHIFT :NUM) 1073742053 4098)
 (:|Return| (:RSHIFT :NUM) 13 4098))

This is not a tutorial. It's a warning. Two friends were talking about this being hard to do, so I wrote this for them. One is my friend https://turtleware.eu and the other is https://tumbleweed.nu.

2. Lisp users will write new languages for our Lisp Games Software Console

Like we saw with CLOS object language, ASDF system creation language and CLIM interface design language in how-to-program-i, the iconic lisp style is to write new languages that solve a domain of problems much better than common lisp does, and then use those. An example is the allegro common lisp video game company, Naughty Dog which was acquired by sony (sony had previously partnered with the lisp company Symbolics). Naughty dog used common lisp to write video game writing languages, their recipe for success.

3. Some Embeddable Common Lisp History

With the rise of C oriented microcomputers (nowadays, we just call them computers or mobile phones) one lisp tradition descended from Kyoto Common Lisp focused on seamless interoperability between C/C++ and common lisp. Every language says they Have An FFI, but having an FFI that sucks, sucks.

The following isn't portable common lisp, and needs to be processed in a special way by Embeddable Common Lisp to be used, but ther lisp user can freely weave between C/C++ and lisp and back.

This language is an awesome and beautiful s-exp language for when people say "There's a C/C++ API!" to you.

It uses allowed extensions as a conformant common lisp, but the new language definitely looks and feels very different, allowing us to write a frankenlisp C/C++ freely.


(ffi:clines "
#include <stdio.h>

#include <SDL2/SDL.h>

SDL_Renderer *renderer;
SDL_Window *window;
SDL_Event e;
")

(defun c-keyname (sdlk) "
sdlk should be an e.key.keysym.sym originating int.
"
  (let ((cstring (ffi:c-inline (sdlk) (:int) :cstring "SDL_GetKeyName(#0)" :one-liner t)))
    (ffi:convert-from-cstring cstring)))

(defun interpret-mods (keymod) "
keymod should be an e.key.keysym.mod originating int.
"
  (let ((mods '((:lshift .    #x1)
                (:rshift .    #x2)
                (:lctrl  .   #x40)
                (:rctrl  .   #x80)
                (:lalt   .  #x100)
                (:ralt   .  #x200)
                (:lgui   .  #x400)
                (:rgui   .  #x800)
                (:num    . #x1000)
                (:caps   . #x2000)
                (:mode   . #x4000)
                (:scroll . #x8000))))
    (loop :for mod :in mods
          :for kw := (car mod)
          :for hx := (cdr mod)
          :unless (zerop (logand hx keymod))
            :collect kw)))

(defun sdl2-receive-keys (&aux (keys ()))
  (let ((key 0) ; int (ie default enum)
        (mod 0)) ; uint16
    (declare (:int key mod))
    (ffi:c-progn (key mod)
   "
if (SDL_Init(SDL_INIT_VIDEO) < 0)
"
   (error "%s failed" 'SDL_INIT_VIDEO)
   "
if (SDL_CreateWindowAndRenderer(
        640, 480, SDL_WINDOW_RESIZABLE,
        &window, &renderer))
"
   (error "%s failed" 'SDL_WINDOW_RESIZABLE)
   "

for (;;) { 
SDL_SetRenderDrawColor(renderer,0,0,0,255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_Delay(25);

while (SDL_PollEvent(&e))
        if (e.type == SDL_QUIT) {
quit:
            SDL_DestroyRenderer(renderer);
            SDL_DestroyWindow(window);
            SDL_Quit();"
            (return-from sdl2-receive-keys (nreverse keys)) "
        } else if (e.type == SDL_KEYDOWN)
            if (e.key.keysym.sym == SDLK_ESCAPE) goto quit;
        else {
            #0 = (int)e.key.keysym.sym;
            #1 = (int)(e.key.keysym.mod & 65475);"
            (push (list (intern (c-keyname key) :keyword)
                        (interpret-mods mod)
                        key
                        mod)
                  keys)
        "}}")))
</div>

4. But what does it mean

I picked the sffi embeddable common lisp language because it is the best language there is for writing and driving C/C++ libraries and executables (eat your heart out, lua).

While ECL purports to conform to common lisp, only ECL can compile and load this, (you normally do this from the ASDF system language but from inside an ecl image).

This is an important case for game cartridges, and it leads me to realise that LAFS (Lisp Game Soft Cons) software console cartridges need to be compiled fasls. This gives sufficient leeway to each game studio to have full control of their own game languages, while conforming to common lisp through cl:compile-file, which produces fasls (compiled lisp files).

Author: Screwlisp

Created: 2024-06-06 Thu 19:07

Validate

Get LISP GAME SOFT CONS

Download NowName your own price

Leave a comment

Log in with itch.io to leave a comment.