CL-Dwaddle  CL-Dwaddle


CL-Dwaddle (or just Dwaddle) is both a library and command line program for manipulating Doom WAD files (and a few other things).

The library focuses primarily on stricter compliance to specifications, with a secondary focus of not being too slow. This is especially true for the UDMF-related functionality. It's meant to offer support for most mapping- and wad-related data structures through CLOS classes and generic functions.

The command line program isn't like most other Doom-related tools. Instead, it focuses on features that I didn't find in other tools, yet realized I still needed or wanted. The result is a set of "modes" that the command line program can run in.

How do I get set up?

Dwaddle is designed to work with SBCL and ClozureCL. It has been regularly tested with SBCL 2.1.0 and (mostly regularly) with CCL 1.11.5.

Most of the dependencies can be fetched with Quicklisp. However, there are a few that you will have to grab manually:

  • p36-lib: A utility library of mine that provides some extra batteries to Common Lisp. Basically my own personal standard lib.
  • cl-remi-log: My own logging library.
  • cl-arg-parser: My own command line library (CLI-only).
  • cl-hjson: My naive HJSON parsing library (CLI-only).

Once you have the dependencies:

  • Clone the repository locally where ASDF can find it.
  • Use ASDF to load the system inside of your Lisp implementation (e.g., (asdf:load-system :dwaddle))

Building the command-line program

Just run build.rb from the root Dwaddle directory - you can use --help to see some options. The resulting binaries will be in a new bin/ directory. Note that this has only been tested in Linux.

Development Info

Dwaddle is divided up into a few packages:

  • :p36.dwaddle: The core package that contains most of the code. Nickname is :dwaddle.
  • :p36.dwaddle.maps: The parsers for various level formats all live here. Nickname is :dwaddle-maps.
  • :p36.dwaddle.cli: The command line program lives in its own package. Each mode also gets its own package, such as :p36.dwaddle.cli.levelimage.

Map parsing is intended to generate a dwaddle:level instance. This class, as well as the related classes (dwaddle:vertex, dwaddle:linedef, dwaddle:sidedef, dwaddle:sector, dwaddle:thing), form the superset of all other map formats. This is currently a one-way street, though I plan to make it two-way eventually. The dwaddle:level class also holds references to two additional collections: dwaddle:level-data and dwaddle:gl-nodes-data. These, when present, contain the rest of the parsed map data (dwaddle:node, dwaddle:seg, dwaddle:gl-subsector, etc.). Nearly all level-related functions expect to operate on these classes.

On the graphics side, the dwaddle:dwaddle-image class is used as an abstraction layer over whatever library I decide to use this week. Its related methods provide some basic image operations. This class is used to represent a final, composited image that can be written to PNG or JPEG or whatever. It does not represent the original graphic data loaded from wads directly. Palette information is stored in a dwaddle:palette, though it's only used when writing a paletted image, or working with the original data directly.

The original data gets loaded into dwaddle:map-texture, dwaddle:doom-picture, and dwadle:flat instances. There's also an abstraction of the PNAMES and TEXTUREx lumps, and convenience methods for loading these into a set of dwaddle:dwaddle-images.

All conditions that are intended to be catchable in the library derive from dwaddle:dwaddle-error. This is also the name of a macro that is used to conveniently construct them. Messages for the conditions can be grabbed using dwaddle:error-text. Conditions that are not ancestors of dwaddle:dwaddle-error represent programming defects.


The library only uses rlog:vlog and rlog:dlog since, except for these purposes, the library should be quiet.

Style info

I use a slightly unorthodox style for my code. Aside from these differences, please use normal Lisp formatting.

  • Keep lines 118 characters or shorter. Obviously sometimes you can't, but please try. Use 115 characters for Markdown files, though.
  • I mark types using the form T/..... For example, T/SOME-NEAT-TYPE. For predicates on these, use SOME-NEAT-TYPE-P.
  • No tabs. Only spaces.