# `Cauldron2D.Projection.Mode7`
[🔗](https://github.com/jaman/cauldron/blob/v0.2.2/cauldron_2d/lib/cauldron_2d/projection/mode7.ex#L1)

Composes the world as a ground plane seen in perspective from above it, turning freely:
the floor recedes to a horizon, movers stand on it as billboards, and everything fades
towards the atlas's void colour with distance.

    Cauldron2D.Projection.Mode7.render(:my_game,
      position: {12.5, 8.5},
      heading: :math.pi() / 2,
      cell: &MyGame.cell/1,
      size: {320, 200},
      movers: [{:hero, {14.5, 8.5}, 0.0}]
    )

The plane is drawn from each cell's `:top` face, so a cell with storeys lies flat like
any other: this projection has no verticality. Use `Cauldron2D.Projection.Iso`,
`Cauldron2D.Projection.Oblique` or `Cauldron2D.Projection.FirstPerson` for a world
whose walls must stand up.

Unlike the isometric view the heading is continuous, so a game may turn by any angle.

## Options

  * `:position` — `{x, y}` in tiles, where the camera is, required
  * `:heading` — radians, `0` along `+x`, required
  * `:cell` — `fn {x, y} -> cell end`, as `Cauldron2D.Surface` takes cells; `:void` is
    drawn as the void colour, required
  * `:size` — `{width, height}` of the picture in pixels, required
  * `:eye` — how far above the plane the camera sits, in tiles. Default `1.6`
  * `:pitch` — `-0.8..0.8`, how far the horizon is moved down or up the picture.
    Default `0.0`
  * `:aspect` — a pixel's width over its height, so a picture drawn into cells that are
    not square keeps its proportions. Default `1.0`
  * `:fov` — the horizontal field of view in degrees. Default `70`
  * `:range` — how many tiles away the plane fades out entirely. Default `24`
  * `:sky` — `{top, bottom}` colours above the horizon. Default a blue gradient
  * `:movers` — `[{art, {x, y}}]` or `[{art, {x, y}, heading}]`; a mover shows its
    `:front` pose when heading towards the camera, `:back` away, `:side` across
    (mirrored one way); with no heading it faces the camera. Default `[]`
  * `:volumes` — coloured regions of space, as `Cauldron2D.Projection.Volume`
    describes them, each tinting the plane and the movers behind it. Default `[]`
  * `:at` — the time in milliseconds an animated art's frame is chosen for. Default `0`

# `option`

```elixir
@type option() ::
  {:position, {number(), number()}}
  | {:heading, number()}
  | {:cell, ({integer(), integer()} -&gt; Cauldron2D.Surface.cell())}
  | {:size, {pos_integer(), pos_integer()}}
  | {:eye, number()}
  | {:pitch, number()}
  | {:aspect, number()}
  | {:fov, number()}
  | {:range, number()}
  | {:sky, {{byte(), byte(), byte()}, {byte(), byte(), byte()}}}
  | {:movers, [tuple()]}
  | {:volumes, [map()]}
  | {:at, integer()}
```

# `project`

```elixir
@spec project(Cauldron2D.Atlas.name() | Cauldron2D.Atlas.t(), {number(), number()}, [
  option()
]) ::
  {float(), float()} | nil
```

Where world point `{x, y}` lands in the picture, or `nil` when it is behind the camera.

# `render`

```elixir
@spec render(Cauldron2D.Atlas.name() | Cauldron2D.Atlas.t(), [option()]) ::
  FrenchCurve.Raster.t()
```

The picture, as the module documentation describes.

# `tile_at`

```elixir
@spec tile_at(Cauldron2D.Atlas.name() | Cauldron2D.Atlas.t(), {number(), number()}, [
  option()
]) ::
  {integer(), integer()} | nil
```

The tile under picture pixel `{px, py}`, or `nil` at or above the horizon.

# `unproject`

```elixir
@spec unproject(
  Cauldron2D.Atlas.name() | Cauldron2D.Atlas.t(),
  {number(), number()},
  [option()]
) ::
  {float(), float()} | nil
```

The world point under picture pixel `{px, py}`, or `nil` at or above the horizon.

---

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