GitHunt
PO

podiki/cl-tcod

Common Lisp CFFI interface for libtcod, the roguelike library (fork for latest libtcod)

Note on this version

This is a working temporary(?) fork of cl-tcod, residing officially
on Bitbucket. I am working with the
official maintainer on these changes, so expect them to be merged back upstream at some
point. For now though, this provides a version of cl-tcod that works with the latest
version (and development) of libtcod, 1.6.2. This is also that version that works with
my Common Lisp port, cl-tcod-tutorial, of the
"Complete Roguelike Tutorial, using python+libtcod".

cl-tcod

The cl-tcod library provides an interface (wrapper) between Common Lisp and
the Doryen Library (libtcod). Libtcod is described on its website as
follows:

libtcod, a.k.a. "The Doryen Library", is a free, fast, portable and
uncomplicated API for roguelike developpers providing an advanced true
color console, input, and lots of other utilities frequently used in
roguelikes.

Files

cl-tcod consists of the following files:

  • tcod.lisp, a lisp file which creates lisp bindings for C functions in the
    compiled libtcod library, using the CFFI lisp foreign function interface.
  • tcod.asd, which allows TCOD to be easily loaded and used as a library by
    other common lisp programs, via the ASDF library-loading facility.
  • tcod-colours.lisp, a lisp file containing definitions for all the colours
    named in /etc/X11/rgb.txt; autogenerated using 'parse-rgb' (see below)
  • parse-rgb.lisp, a lisp file containing code for parsing /etc/X11/rgb.txt
    and generating tcod-colours.lisp
  • parse-rgb.asd, ASDF system definition file for parse-rgb.lisp

cl-tcod has been tested with SBCL 1.1.0 on Linux, Mac OSX Mountain Lion
and Windows, Clozure Common Lisp 1.5 on Linux and Windows, and
Clisp on Windows.

License

The cl-tcod package is placed in the Public Domain by its author.

Dependencies

cl-tcod depends on the following libraries:

Installation

You need to know your way around your chosen common lisp and how to install and
load lisp libraries before proceeding. You also need to have a version of
libtcod newer than 1.4.1rc2, which is the first version that includes the
wrappers.c and wrappers.h source files that allow cl-tcod to interface
with libtcod.

  1. Ensure you have a working common lisp installation.

  2. Ensure either Quicklisp or the ASDF lisp
    library is installed.

  3. If CFFI or defstar are not installed, download and install them
    somewhere ASDF can find them. CFFI requires several third-party lisp
    libraries -- see the CFFI documentation for more details. Note that if you
    have Quicklisp installed, you can install CFFI and its dependencies easily
    using the command (ql:quickload "cffi") at the Lisp prompt.

  4. Put the cl-tcod files in a directory where ASDF can find them.

  5. Make sure libtcod is installed and compiled. Make sure the libtcod
    dynamically linked library (.dll, .so or .dylib file) is somewhere your lisp
    system can find it. It probably is, but if CFFI complains about being unable
    to find the library, you can either copy it to an appropriate directory or
    add its directory to the list variable cffi:*foreign-library-directories*
    e.g. by typing the following in the lisp interpreter:

    :::cl
    (push #P"/my/libtcod/directory/" cffi:*foreign-library-directories*)
    

    On windows, .dll files should be put in one of the directories listed in the
    PATH environment variable. You will need to put SDL.dll in the same place
    if you don't already have SDL installed.

    On Linux, you can usually put .so files in /usr/local/lib/.
    Use your package installer to install libSDL.
    Try running the libtcod demo programs to check everything works.

  6. Start lisp, then load cl-tcod. Using Quicklisp:

    :::cl
    (ql:quickload :tcod)
    

    Using ASDF:

    :::cl
    (load "/path/to/asdf/asdf.lisp")
    (asdf:oos 'asdf:load-op :tcod)
    
  7. Type something like the following commands at the lisp prompt to start using
    libtcod from within Lisp. Alternatively you can type (tcod:hello-world),
    which is a function containing the code below.

    :::cl
    (tcod:console-set-custom-font "terminal.png" '(:font-layout-ascii-in-row) 16 16)
    (tcod:console-init-root 80 25 "Test" nil :renderer-sdl)
    (tcod:console-clear tcod:*root*)
    (tcod:console-print tcod:*root* 1 1 "Hello, world!~%")
    (tcod:console-wait-for-keypress t)
    

Differences between CL-TCOD and libtcod

Naming conventions

The C function TCOD_foo_bar corresponds to the lisp function foo-bar, which
is in the tcod package (and so requires a prefix of tcod: to access in most
situations). Underscores become hyphens. So:

:::cl
(tcod:foobar-function a b)    ; = TCOD_foobar_function(a, b)

Predicate functions' are functions whose main job is to return a boolean value, true (non nil) or false (nil`), that answers a question. These have a
terminal '?' added to their name:

:::cl
(tcod:console-is-fullscreen?)    ; TCOD_console_is_fullscreen()

C enums have generally more succinct names. As they are lisp keywords, their
names all begin with a colon :. THey are named according to the following
pattern:

:::cl
:backspace         ;  TCODK_BACKSPACE (etc)
:char-hline        ;  TCOD_CHAR_HLINE  (etc)
:colctrl-1         ;  TCOD_COLCTRL_1  (etc)
:set               ;  TCOD_BKGND_SET (etc)
:font-layout-ascii-in-col   ;  TCOD_FONT_LAYOUT_ASCII_INCOL
:fov-shadow        ;  FOV_SHADOW
:key-pressed       ;  TCOD_KEY_PRESSED
:center, :centre   ;  CENTER

In general, most functions exist in both U.S. and non-U.S. spellings, This is
mainly relevant to those functions with colour/color or centre/center in their
names.

Colournums

In libtcod, colours are represented as structures containing three integer
values: red, green and blue (each 0-255). The name of the structure type is
TCOD_color_t.

In cl-tcod, these colour structs are converted into 3-byte integers using the C
functions int_to_color(int) and color_to_int(TCOD_color_t), both defined in
wrappers.c. The 3 bytes are red, green and blue in order (blue is 1's). ie:

:::C
struct TCOD_color_t {r, g, b}    /* becomes #x00RRGGBB */

So, for example, one way to use the function TCOD_color_multiply_scalar()
from lisp is:

:::cl
(tcod:color-multiply-scalar (tcod:compose-colour 218 165 32) 0.5)

All C functions that take or return TCOD_color_t structs, are wrapped by lisp
functions that take or return integers as described above.

Colours by keyword

A lisp keyword is any symbol beginning with a colon :. In lisp, keywords
(like all symbols) are first-class values and can be passed around just like
any other value. cl-tcod uses keywords to refer to particular colours, for
example the keyword :cyan refers to the colour #x0056A3CD (or 5678029 in
decimal notation).

You can use keywords instead of colournums as arguments to lisp functions, by
using the function colour to return the colournum associated with a keyword:

:::cl
(tcod:colour :cyan)    ; returns 5678029

You can also define your own colour names, like so:

:::cl
(tcod:make-colour :my-goldenrod 218 165 32)
(tcod:color-multiply-scalar (tcod:colour :my-goldenrod) 0.5)

cl-tcod knows all the colour names defined in the "rgb.txt" file under
Xwindows -- :navajo-white, :honeydew, :mint-cream, and so on. There is
nothing special about the fact that rgb.txt comes from Xwindows -- the colours
are just named R,G,B values and can be used anywhere that cl-tcod can be
used. Look in the source file tcod-colours.lisp to see the available colour
names. If you are using [[http://www.gnu.org/software/emacs/][GNU Emacs]], do
M-x list-colors-display to see a list of all colours.

Lisp format versus C printf

The TCOD functions that accept printf-like string-formatting arguments, have
been modified to instead accept arguments to Common Lisp's much more capable
format function. For example:

:::C
TCOD_console_print (con, x, y, "Printing at %d, %dn", x, y);

becomes:

:::cl
(tcod:console-print con x y "Printing at ~D, ~D~%" x y)

Miscellaneous extra functions

console-print-double-frame is like console-print-frame, but draws using
`double-line' characters:

:::cl
(tcod:console-print-double-frame CONSOLE X Y W H EMPTY? STRING...)

Coverage

Does not provide wrappers for:

  • File parser. Using this from lisp would be a very cumbersome way to read
    values from a file, as the resulting values are not lisp objects. You would
    be better to either consider using the lisp
    read function, or looking into lisp libraries for parser generation.
  • namegen-get-sets -- I haven't yet implemented this as it will have to
    involve converting from libtcod's bespoke 'linked list' to a lisp list.
    You may be better to write your random name generator in lisp (fairly trivial).
  • sys-get-directory-content, sys-file-exists, sys-is-directory,
    sys-delete-file: Common Lisp already has functions that do the same thing.
podiki/cl-tcod | GitHunt