mode-lambda:   the best 2D graphics of the 90s, today!
1 mode-lambda drawing model
2 mode-lambda static:   sprite libraries
make-sprite-db
sprite-db?
sprite-attributes?
add-sprite!
add-sprite!/  bm
add-sprite!/  file
add-sprite!/  value
add-palette!
add-palette!/  file
save-csd!
compile-sprite-db
3 mode-lambda edition:   amazing graphics
PALETTE-DEPTH
compiled-sprite-db?
load-csd/  bs
load-csd
sprite-idx
palette-idx
sprite-width
sprite-height
sprite
sprite-data?
sprite-data-dx
sprite-data-dy
sprite-data-mx
sprite-data-my
sprite-data-spr
sprite-data-layer
layer
4 mode-lambda color:   basic color theory
GRAY
TRANSPARENT
BLACK
WHITE
argb
color?
alpha
red
green
blue
color->palette
color->tint
color->shades
color-wheel
complement-idxs
analogous-idxs
triadic-idxs
split-complementary-idxs
tetradic-idxs
square-idxs
polygon-idxs
5 mode-lambda text:   text layout
5.1 Static
*ALL-ASCII*
load-font!
5.2 Runtime
font?
font-char-idx
make-text-renderer
6 mode-lambda gl:   premier backend
stage-draw/  dc
gui-mode
gl-backend-version
gl-filter-mode
gl-smoothing?
gl-screenshot!
7 mode-lambda software:   discount backend
stage-draw/  dc
gui-mode
software-bitmap-path
8 mode-lambda shot:   screenshot helpers
screenshot-in-dir!
8.12

mode-lambda: the best 2D graphics of the 90s, today!🔗ℹ

Jay McCarthy

The mode-lambda package provides a set of libraries for creating high-performance 2D graphics. Try running racket -l mode-lambda/examples/one to see what it can do.

    1 mode-lambda drawing model

    2 mode-lambda static: sprite libraries

    3 mode-lambda edition: amazing graphics

    4 mode-lambda color: basic color theory

    5 mode-lambda text: text layout

      5.1 Static

      5.2 Runtime

    6 mode-lambda gl: premier backend

    7 mode-lambda software: discount backend

    8 mode-lambda shot: screenshot helpers

1 mode-lambda drawing model🔗ℹ

mode-lambda renders rectangular bitmaps (called sprites) in a pixel-perfect manner on a rendering surface. The size of the rendering surface is fixed ahead-of-time when the backend is initialized. When drawn, the rendering surface is then scaled to fit the display environment’s drawing surface. mode-lambda follows an ahead-of-time, staged rendering regime whereby all color data must be "compiled", using compile-sprite-db, before any drawing can occur.

mode-lambda draws sprites on to one of the layers. The larger layers are on-top, with transparent pixels seeping through. mode-lambda makes no guarantees about the layering and transparency behavior of sprites within a single layer. Each layer may have an independent center point, width, scaling coefficients, rotation, wrapping behavior, and Mode-7 coefficients.

Varying the center point (cx & cy) over time creates a scrolling effect given stationary sprites on the layer. When the scrolling effect is combined with a larger or smaller frame (hw & hh) that the rendering surface, this produces a clipping effect. The scaling coefficients (mx & my) allow the entire layer to be zoomed in and out. (A scaling change over time is used in many SNES RPGs to initiate combat.) The rotation coefficient (theta) rotates the entire layer when it is drawn. The wrapping behavior (wrap-x? & wrap-y?) allows sprites that overlap with the vertical (or horizontal) edge of the screen to be partly drawn on the opposite side. Any of these changes could be implemented in software by the mode-lambda client, but the layer configuration provides a more efficient implementation.

Finally, the Mode-7 coefficients create a perspective effect whereby the horizon is defined to be a particular Y value (horiz) and then sprites are gradually scaled towards the viewer who has a particular field of view (fov). Specifically:
  • When mode7-coeff is 0, then there is no effect.

  • When mode7-coeff is 1, then the horizon defines a "ceiling".

  • When mode7-coeff is 2, then the horizon defines a "floor". This is the most common usage of Mode-7 and is used in Mario Kart for the track and many RPGs for the world map.

  • When mode7-coeff is 3, then the horizon defines the middle of "cylinder".

It is easiest to understand this effect by looking at some screenshots of SNES games. (Although, mode-lambda does not support as powerful of a Mode-7 effect, because the parameters cannot be changed per Y line, but all common uses are supported.)

When mode-lambda draws a sprite, that sprite instance is associated with a palette of 16 colors. If the palette is 0, then the sprite bitmap color data is directly consulted for the color to render. Otherwise, only the green value of the sprite’s color data is used and it is used after scaling it down by 14 as an offset into the given palette.

Each sprite instance has many drawing paramters. The most important is its center point (cx & cy) and which sprite is to be drawn (spr-idx). Next, the layer (layer) and palette (pal-idx) can be specified as mentioned previously. The color of the pixels can be further influenced by a color tint. The given alpha value (a) is multiplied with the sprite/palette color, while the diffuse colors (r, g, and b) are added. Finally, each sprite may be independently scaled in the X (mx) or Y (my) direction and may be independently rotated (theta).

Each rendering pass of mode-lambda receives two trees of sprite instances. The first is called the "static" sprites and the second are the "dynamic" sprites. The static sprites are always drawn first on a given layer. Aside from this, they are treated equally, but mode-lambda will guarantee that if a tree is eq? to the tree from the last frame, the GPU’s data will not be refreshed. This guarantees that static level geometry is uploaded once, if it never changes, so mode-lambda programs should factor their graphics into static and dynamic pieces for performance.

mode-lambda is extremely memory efficient. Each sprite instance consumes 32 bytes on the CPU and the GPU. If a GPU supported one gigabyte per second memory transfer, then about 550,000 sprites would be supported at 60 FPS. Given that most GPUs support many gigabytes per second memory transfer rates, this means that performance is almost always dominated by the mode-lambda client’s preparation of the sprite trees and mode-lambda rendering can be treated as free.

2 mode-lambda static: sprite libraries🔗ℹ

 (require mode-lambda/static) package: mode-lambda

Use this module to construct a database of sprites that your program will display. This can be run offline and the result saved persistently with save-csd!.

procedure

(make-sprite-db)  sprite-db?

Returns a sprite database.

procedure

(sprite-db? x)  boolean?

  x : any/c
Identifies values returned by make-sprite-db.

procedure

(sprite-attributes? x)  boolean?

  x : any/c
Identifies a vector with 5 elements. The first (n) is a symbol?, the second (pal) is either #f or a symbol?, the third (w) and fouth (h) are 16-bit exact-nonnegative-integer?, and the fifth (bs) is a bytes? describing the ARGB pixels of the sprite. bs must be (* 4 w h) long. If pal is not false, then the palette pal is used to interpret the pixel values into palette offsets.

procedure

(add-sprite! db load-spr)  void?

  db : sprite-db?
  load-spr : (-> sprite-attributes?)
Adds the sprite returned by load-spr to db.

procedure

(add-sprite!/bm db n load-bm [#:palette pal])  void?

  db : sprite-db?
  n : symbol?
  load-bm : 
(-> (or/c path-string? input-port?
          (is-a?/c bitmap%)))
  pal : (or/c #f symbol?) = #f
Adds the sprite returned by load-bm to db using the name n. If pal is not false, then the palette named is consulted to interpret the bitmap pixel values into palette offsets.

procedure

(add-sprite!/file db n file [#:palette pal])  void?

  db : sprite-db?
  n : symbol?
  file : path-string?
  pal : (or/c #f symbol?) = #f
Adds the sprite inside file to db using the name n. If pal is not false, then the palette named is consulted to interpret the bitmap pixel values into palette offsets.

procedure

(add-sprite!/value db n val [#:palette pal])  void?

  db : sprite-db?
  n : symbol?
  val : convertible?
  pal : (or/c #f symbol?) = #f
Adds the sprite val to db using the name n. If pal is not false, then the palette named is consulted to interpret the bitmap pixel values into palette offsets.

procedure

(add-palette! db n cs)  void?

  db : sprite-db?
  n : symbol?
  cs : (listof color?)
Adds the palette cs to db with the name n.

procedure

(add-palette!/file db n file)  void?

  db : sprite-db?
  n : symbol?
  file : path-string?
Adds the palette inside file, which is expected to be a 1xPALETTE-DEPTH bitmap to db with the name n.

procedure

(save-csd! cdb path [#:debug? debug?])  void?

  cdb : compiled-sprite-db?
  path : path-string?
  debug? : boolean? = #f
Saves the compiled database db into the directory path with the name "csd.rktd.gz". If debug? is #t, then the sprite atlas and palette is saved in the directory as PNG files.

procedure

(compile-sprite-db db [#:padding padding])  compiled-sprite-db?

  db : sprite-db?
  padding : exact-positive-integer? = 1
Compiles the database db. A border of padding pixels is added to each sprite to prevent color data bleeding across sprites in the atlas texture.

3 mode-lambda edition: amazing graphics🔗ℹ

 (require mode-lambda) package: mode-lambda

Use this module to construct scenes for one of the backends. Connect it to mode-lambda/static with load-csd.

The number of colors in one palette supported by mode-lambda. Currently 16.

procedure

(compiled-sprite-db? x)  boolean?

  x : any/c
Identifies values returned by compile-sprite-db.

procedure

(load-csd/bs bs)  compiled-sprite-db?

  bs : bytes?
Loads the compiled database from the bytes bs.

procedure

(load-csd path)  compiled-sprite-db?

  path : path-string?
Loads the compiled database from the directory path.

procedure

(sprite-idx cdb n)  (or/c #f exact-nonnegative-integer?)

  cdb : compiled-sprite-db?
  n : symbol?
Looks up the index for the sprite n in cdb.

procedure

(palette-idx cdb n)  (or/c #f exact-nonnegative-integer?)

  cdb : compiled-sprite-db?
  n : symbol?
Looks up the index for the palette n in cdb.

procedure

(sprite-width cdb spr-idx)  exact-nonnegative-integer?

  cdb : compiled-sprite-db?
  spr-idx : exact-nonnegative-integer?
Returns the width of spr-idx in cdb.

procedure

(sprite-height cdb spr-idx)  exact-nonnegative-integer?

  cdb : compiled-sprite-db?
  spr-idx : exact-nonnegative-integer?
Returns the height of spr-idx in cdb.

procedure

(sprite cx    
  cy    
  spr-idx    
  [#:layer layer    
  #:r r    
  #:g g    
  #:b b    
  #:a a    
  #:pal-idx pal-idx    
  #:m m    
  #:mx mx    
  #:my my    
  #:theta theta])  sprite-data?
  cx : flonum?
  cy : flonum?
  spr-idx : exact-nonnegative-integer?
  layer : byte? = 0
  r : byte? = 0
  g : byte? = 0
  b : byte? = 0
  a : flonum? = 1.0
  pal-idx : exact-nonnegative-integer? = 0
  m : flonum? = 1.0
  mx : flonum? = m
  my : flonum? = m
  theta : flonum? = 0.0
Returns a sprite instance.

procedure

(sprite-data? x)  boolean?

  x : any/c
Identifies sprite data.

procedure

(sprite-data-dx s)  flonum?

  s : sprite-data?
Returns X offset.

procedure

(sprite-data-dy s)  flonum?

  s : sprite-data?
Returns Y offset.

procedure

(sprite-data-mx s)  flonum?

  s : sprite-data?
Returns X scale.

procedure

(sprite-data-my s)  flonum?

  s : sprite-data?
Returns Y scale.
Returns sprite index.

procedure

(sprite-data-layer s)  byte?

  s : sprite-data?
Returns sprite layer.

procedure

(layer cx    
  cy    
  [#:hw hw    
  #:hh hh    
  #:wrap-x? wrap-x?    
  #:wrap-y? wrap-y?    
  #:mx mx    
  #:my my    
  #:theta theta    
  #:mode7 mode7-coeff    
  #:horizon horiz    
  #:fov fov])  layer-data?
  cx : flonum?
  cy : flonum?
  hw : flonum? = +inf.0
  hh : flonum? = +inf.0
  wrap-x? : boolean? = #f
  wrap-y? : boolean? = #f
  mx : flonum? = 1.0
  my : flonum? = 1.0
  theta : flonum? = 0.0
  mode7-coeff : flonum? = 0.0
  horiz : flonum? = 0.0
  fov : flonum? = 1.0
Returns a layer configuration.

4 mode-lambda color: basic color theory🔗ℹ

 (require mode-lambda/color) package: mode-lambda

This module defines helpers for creating color palettes for mode-lambda.

value

GRAY : color?

The color gray.
The transparent color.

value

BLACK : color?

The color black.

value

WHITE : color?

The color white.

procedure

(argb a r g b)  color?

  a : byte?
  r : byte?
  g : byte?
  b : byte?
Constructs a color object.

procedure

(color? x)  boolean?

  x : any/c
Identifies colors.

procedure

(alpha c)  byte?

  c : color?
Extracts the alpha value of c.

procedure

(red c)  byte?

  c : color?
Extracts the red value of c.

procedure

(green c)  byte?

  c : color?
Extracts the green value of c.

procedure

(blue c)  byte?

  c : color?
Extracts the blue value of c.

procedure

(color->palette base)  (listof color?)

  base : color?
Returns a list of colors where the first color is TRANSPARENT, the next is BLACK, followed by 7 shades of base, base, 7 tints of base, and then WHITE.

procedure

(color->tint base how-many)  (listof color?)

  base : color?
  how-many : exact-nonnegative-integer?
Returns how-many tints of base. Tints are brighter than their base color.

procedure

(color->shades base how-many)  (listof color?)

  base : color?
  how-many : exact-nonnegative-integer?
Returns how-many shades of base. Shades are darker than their base color.

procedure

(color-wheel how-many [#:s s #:b b])  (listof color?)

  how-many : exact-nonnegative-integer?
  s : (real-in 0.0 1.0) = 1.0
  b : (real-in 0.0 1.0) = 1.0
Takes how-many evenly spaced samples of the color wheel with saturation s and brightness b.

procedure

(complement-idxs how-many)  (listof vector?)

  how-many : exact-nonnegative-integer?
Returns a list of 2-vectors that contain indexes into a color wheel of size how-many where each pair are complementary colors.

procedure

(analogous-idxs how-many)  (listof vector?)

  how-many : exact-nonnegative-integer?
Returns a list of 3-vectors that contain indexes into a color wheel of size how-many where each triple are analogous colors.

procedure

(triadic-idxs how-many)  (listof vector?)

  how-many : exact-nonnegative-integer?
Returns a list of 3-vectors that contain indexes into a color wheel of size how-many where each triple are triadic colors.

procedure

(split-complementary-idxs how-many)  (listof vector?)

  how-many : exact-nonnegative-integer?
Returns a list of 3-vectors that contain indexes into a color wheel of size how-many where each triple are split complementary colors.

procedure

(tetradic-idxs how-many)  (listof vector?)

  how-many : exact-nonnegative-integer?
Returns a list of 4-vectors that contain indexes into a color wheel of size how-many where each quadruple are tetradic colors.

procedure

(square-idxs how-many)  (listof vector?)

  how-many : exact-nonnegative-integer?
Returns a list of 4-vectors that contain indexes into a color wheel of size how-many where each quadruple are square colors.

procedure

(polygon-idxs n how-many)  (listof vector?)

  n : exact-nonnegative-integer?
  how-many : exact-nonnegative-integer?
Returns a list of n-vectors that contain indexes into a color wheel of size how-many where each vector of colors are on the vertix of a regular n-gon. (This is a generalization of triadic-idxs and square-idxs.)

5 mode-lambda text: text layout🔗ℹ

 (require mode-lambda/text) package: mode-lambda

This module captures some convenience functions for adding font glyphs to the sprite database and laying out horizontal text.

5.1 Static🔗ℹ

 (require mode-lambda/text/static) package: mode-lambda

A list of all graphical ASCII characters.

procedure

(load-font! db    
  [#:size size    
  #:face face    
  #:family family    
  #:style style    
  #:weight weight    
  #:underlined? underlined?    
  #:smoothing smoothing    
  #:size-in-pixels? size-in-pixels    
  #:hinting hinting    
  #:alphabet alphabet])  font?
  db : sprite-db?
  size : (real-in 0.0 1024.0) = 12
  face : (or/c string? #f) = #f
  family : 
(or/c 'default 'decorative 'roman 'script
      'swiss 'modern 'symbol 'system)
 = 'default
  style : (or/c 'normal 'italic 'slant) = 'normal
  weight : (or/c 'normal 'bold 'light) = 'normal
  underlined? : any/c = #f
  smoothing : 
(or/c 'default 'partly-smoothed
      'smoothed 'unsmoothed)
 = 'default
  size-in-pixels : any/c = #f
  hinting : (or/c 'aligned 'unaligned) = 'aligned
  alphabet : (listof char?) = *ALL-ASCII*
Uses most of its arguments to call make-font from racket/draw to construct a font object, which it uses to add all of the characters in alphabet to db and returns a font object for use with font-glyph-idx.

5.2 Runtime🔗ℹ

 (require mode-lambda/text/runtime) package: mode-lambda

procedure

(font? x)  boolean?

  x : any/c
Identifies objects returned from load-font!.

procedure

(font-char-idx the-font cdb char)  exact-nonnegative-integer?

  the-font : font?
  cdb : compiled-sprite-db?
  char : char?
Looks up the character identifier of the character char of the font the-font in the databvase cdb.

procedure

(make-text-renderer f cdb)  
(->i ([text string?]
      [tx real?]
      [ty real?])
     ([#:layer l byte?]
      [#:mx mx real?]
      [#:my my real?]
      [#:r r byte?]
      [#:g g byte?]
      [#:b b byte?]
      [#:a a (real-in 0.0 1.0)])
     any/c)
  f : font?
  cdb : compiled-sprite-db?
Returns a tree of sprites for the glyphs of the string text such that the center is (tx, ty). The sprite are created with the sprite parameters given in the optional arguments.

6 mode-lambda gl: premier backend🔗ℹ

 (require mode-lambda/backend/gl) package: mode-lambda

This is the production backend for mode-lambda. It is pretty fast, but kind of complicated.

value

stage-draw/dc

 : 
(->i ([cdb compiled-sprite-db?]
      [render-width exact-nonnegative-integer?]
      [render-height exact-nonnegative-integer?]
      [layers byte?])
     (->i ([layer-config (vectorof layer-data?)]
           [static-st any/c]
           [dynamic-st any/c])
          (#:r [r byte?]
           #:g [g byte?]
           #:b [b byte?])
          (->i ([draw-width exact-nonnegative-integer?]
                [draw-height exact-nonnegative-integer?]
                [dc any/c])
               any)))
Prepares a function that accepts rendering states and returns a function that draws that rendering state, with optionally specified background color. layers must be less than or equal to GL_MAX_ARRAY_TEXTURE_LAYERS, which is at least 256, but typically 2048.

value

gui-mode : symbol?

A symbol to be sent to make-gui of lux/chaos/gui.

value

gl-backend-version : (parameter/c (one-of '3.3 'es3.1))

Sets the desired version of OpenGL to use.

This parameter controls the screen filter used to magnify the render surface on to the drawing surface. The default mode 'std, uses sharp pixel-duplicating filtering. The 'crt mode simulates a CRT.

value

gl-smoothing? : (parameter/c (or/c #f #t))

This parameter controls whether to blend sprite pixels across screen pixels. The default is #f, showing sharp sprite pixels. Set to #t to smooth sprites across screen pixels.

value

gl-screenshot! : 
(parameter/c (-> exact-nonnegative-integer?
                 exact-nonnegative-integer?
                 exact-nonnegative-integer?
                 bytes?
                 void?))
If this value is not #f, then it is called once for each layer with (a) the layer identifier, (b) the width of the layer, (c) the height of the layer, and (d) the raw pixel values in ARGB order. Enabling this drastically lowers rendering performance because it forces a pixel buffer read and synchronization.

(screenshot-in-dir! dir) from mode-lambda/shot is an ideal value for this parameter.

7 mode-lambda software: discount backend🔗ℹ

 (require mode-lambda/backend/software)
  package: mode-lambda

This is the reference backend for mode-lambda. It is very slow, and a little complicated, but easier to test than mode-lambda/backend/gl.

value

stage-draw/dc

 : 
(->i ([cdb compiled-sprite-db?]
      [render-width exact-nonnegative-integer?]
      [render-height exact-nonnegative-integer?]
      [layers byte?])
     (->i ([layer-config (vectorof layer-data?)]
           [static-st any/c]
           [dynamic-st any/c])
          (#:r [r byte?]
           #:g [g byte?]
           #:b [b byte?])
          (->i ([draw-width exact-nonnegative-integer?]
                [draw-height exact-nonnegative-integer?]
                [dc any/c])
               any)))
Prepares a function that accepts rendering states and returns a function that draws that rendering state.

value

gui-mode : symbol?

A symbol to be sent to make-gui of lux/chaos/gui.

This parameter controls the path that the post-rendering bitmap is saved to disk. The default is to not save screenshots.

8 mode-lambda shot: screenshot helpers🔗ℹ

 (require mode-lambda/shot) package: mode-lambda

Saves the screenshots that gl-screenshot! generates in p.