Cauldron2D.Sectors.Frame (Cauldron2D v0.2.2)

Copy Markdown View Source

An indexed-colour picture drawn a column, a plane or a line at a time — the drawing a sector view does — and turned into RGBA through a palette at the end.

frame =
  Frame.new(320, 200)
  |> Frame.fill(0)
  |> Frame.columns(pictures, [Frame.column(x, {top, bottom}, wall, {texel_x, v, step}, light)])
  |> Frame.plane(pictures, plane, tops, bottoms)

Frame.to_raster(frame, palette)

Every drawing call takes a frame and gives one back, and the frame given back is the one to keep drawing on. Where the NIF loaded the frame is drawn on in place, so a frame must be drawn on by one process at a time, and an earlier value of it is the same frame.

Columns

column/6 describes one vertical run of pixels at screen column x from row top to row bottom, filled from the picture at {texel_x, v, step}: from picture column texel_x, row top reading the picture at row v and each row below step further on. The texel goes through light table light. A plain column wraps both its picture column and its rows, as a wall texture repeats. With masked: true neither wraps — rows outside the picture and transparent texels are skipped — which is how a sprite is drawn. With shimmer: true the column draws no texels: each pixel takes the colour of a pixel a row above or below it already on the frame, through light, for a figure seen as a blur.

Planes

plane/5 fills, column by column, the rows between tops and bottoms with a horizontal plane seen in perspective: a floor or a ceiling at height above the eye (negative below it), textured with its picture tiled across the world one texel per unit, its world x along the picture's columns and its world -y along the rows. Each pixel's light table is start - floor(fade / distance), clamped to the tables, or fixed where that is not -1. With sky: true the plane is not perspective at all: the picture is wrapped around the view, sky_columns picture columns per radian of heading, its rows from sky_mid at the horizon down by sky_step a pixel, drawn through fixed's table or table 0.

The view a plane is drawn for is x, y and angle (radians, 0 along +x, the world's +y up and to the left of the screen) with the eye at screen center_x, center_y, and focal_x, focal_y the distances in pixels at which one world unit spans one pixel across and down.

available?/0 says whether the NIF loaded; where it did not, every call draws the same picture in Elixir, many times slower.

Summary

Functions

Whether the NIF is loaded and drawing is done in C.

One column for columns/3. Options: masked: true, shimmer: true; see the moduledoc.

The columns, as column/6 made them, drawn in order: a list or one binary of them.

Every pixel set to colour.

Straight lines, [{x0, y0, x1, y1, colour}], end points included and clipped to the frame.

A frame of width by height, every pixel colour 0. native: false draws it in Elixir.

The frame's colour indexes, row by row.

A plane, as the moduledoc describes, between tops and bottoms: one row each per column from x1 to x2.

The frame as RGBA through palette, 256 colours of three bytes each.

The frame as a raster through palette.

Types

plane()

@type plane() :: %{
  :x1 => non_neg_integer(),
  :x2 => non_neg_integer(),
  :picture => non_neg_integer(),
  :height => number(),
  :x => number(),
  :y => number(),
  :angle => number(),
  :center_x => number(),
  :center_y => number(),
  :focal_x => number(),
  :focal_y => number(),
  optional(:sky) => boolean(),
  optional(:start) => integer(),
  optional(:fade) => number(),
  optional(:fixed) => integer(),
  optional(:sky_columns) => number(),
  optional(:sky_mid) => number(),
  optional(:sky_step) => number()
}

t()

@type t() :: %Cauldron2D.Sectors.Frame{
  height: pos_integer(),
  native: reference() | nil,
  pixels: binary() | nil,
  width: pos_integer()
}

Functions

available?()

@spec available?() :: boolean()

Whether the NIF is loaded and drawing is done in C.

column(x, arg1, picture, arg2, light, opts \\ [])

@spec column(
  integer(),
  {integer(), integer()},
  non_neg_integer(),
  {integer(), number(), number()},
  non_neg_integer(),
  keyword()
) :: binary()

One column for columns/3. Options: masked: true, shimmer: true; see the moduledoc.

columns(frame, pictures, records)

@spec columns(t(), Cauldron2D.Sectors.Pictures.t(), iodata()) :: t()

The columns, as column/6 made them, drawn in order: a list or one binary of them.

fill(frame, colour)

@spec fill(t(), byte()) :: t()

Every pixel set to colour.

lines(frame, lines)

@spec lines(t(), [{integer(), integer(), integer(), integer(), byte()}]) :: t()

Straight lines, [{x0, y0, x1, y1, colour}], end points included and clipped to the frame.

new(width, height, opts \\ [])

@spec new(pos_integer(), pos_integer(), keyword()) :: t()

A frame of width by height, every pixel colour 0. native: false draws it in Elixir.

pixels(frame)

@spec pixels(t()) :: binary()

The frame's colour indexes, row by row.

plane(frame, pictures, plane, tops, bottoms)

@spec plane(t(), Cauldron2D.Sectors.Pictures.t(), plane(), [integer()], [integer()]) ::
  t()

A plane, as the moduledoc describes, between tops and bottoms: one row each per column from x1 to x2.

rgba(frame, palette)

@spec rgba(t(), binary()) :: binary()

The frame as RGBA through palette, 256 colours of three bytes each.

to_raster(frame, palette)

@spec to_raster(t(), binary()) :: FrenchCurve.Raster.t()

The frame as a raster through palette.