# `Cauldron2D.Sectors.Frame`
[🔗](https://github.com/jaman/cauldron/blob/v0.2.2/cauldron_2d/lib/cauldron_2d/sectors/frame.ex#L1)

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.

# `plane`

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

# `t`

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

# `available?`

```elixir
@spec available?() :: boolean()
```

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

# `column`

```elixir
@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`

```elixir
@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`

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

Every pixel set to `colour`.

# `lines`

```elixir
@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`

```elixir
@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`

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

The frame's colour indexes, row by row.

# `plane`

```elixir
@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`

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

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

# `to_raster`

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

The frame as a raster through `palette`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
