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

Composes a view of the world on a square grid seen from above and in front: floors as
squares, standing arts as a front face with their top above it, movers upright.

    Cauldron2D.Projection.Oblique.compose(:my_game,
      focus: {12.5, 8.5},
      cell: &MyGame.cell/1,
      size: {320, 200},
      movers: [{:hero, {12.5, 8.5}, heading}]
    )

A tile of `t` pixels is drawn `t` wide and `t * squash` tall, and each storey raises
what stands on it by `t * rise` pixels, so a wall shows `rise` of its side and the
ground behind it is covered. Rows are painted back to front.

At the default single facing `+x` runs right and `+y` runs down and towards the viewer.
At four facings the view turns in quarters, which leaves the grid square on the screen,
so nothing is resampled; a mover's pose is read from where it heads on the screen rather
than in the world.

## Options

  * `:focus` — `{x, y}` in tiles, the world point at the picture's centre, required
  * `:cell` — `fn {x, y} -> cell end`, as `Cauldron2D.Surface` takes cells, required
  * `:size` — `{width, height}` of the picture in pixels, required
  * `:squash` — a row's height as a fraction of the tile, `0.25..1.0`. Default `0.5`
  * `:facings` — `1` or `4`, how many steps make a full turn. Default `1`, which is
    fixed and ignores `:facing`
  * `:facing` — which quarter the view is turned to, `0` to `3`, counted the way `+x`
    turns towards `-y`. Whole numbers only. Default `0`
  * `:rise` — a storey's height as a fraction of the tile, `0.25..2.0`. Default `0.75`
  * `:movers` — `[{art, {x, y}}]` or `[{art, {x, y}, heading}]` in tiles, `heading` in
    radians with `0` along `+x`. A mover shows its `:front` pose when heading towards
    the viewer and `:back` when away, mirrored when heading left; with no heading it
    faces the viewer. Default `[]`
  * `:labels` — `[{text, {x, y}, colour}]` or with a fourth element of options as
    `Cauldron2D.Surface.compose/4` takes them, positioned by the tile. Default `[]`
  * `:volumes` — coloured regions of space, as `Cauldron2D.Projection.Volume`
    describes them, each tinting the rows behind it. Default `[]`
  * `:at` — the time in milliseconds an animated art's frame is chosen for. Default `0`

`project/2`, `unproject/2` and `tile_at/2` map between picture pixels and world tiles
for the same options; they answer for the ground, ignoring what stands on it.

# `option`

```elixir
@type option() ::
  {:focus, {number(), number()}}
  | {:cell, ({integer(), integer()} -&gt; Cauldron2D.Surface.cell())}
  | {:size, {pos_integer(), pos_integer()}}
  | {:squash, number()}
  | {:facing, integer()}
  | {:facings, 1 | 4}
  | {:rise, number()}
  | {:movers, [tuple()]}
  | {:labels, [tuple()]}
  | {:volumes, [map()]}
  | {:at, integer()}
```

# `cells`

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

The cells this picture shows, each as `{position, tile}` with the tile the `:cell`
function gave for it.

Cells the function answered `:void` for are left out.

# `compose`

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

The picture, as the module documentation describes.

# `ground_map`

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

The ground as a straight walk across the picture: `{origin, across, down}`, the world
point at the top-left pixel and the world it moves one pixel right and one pixel down.

The ground map is exact, so `origin + px * across + py * down` is the world point
`unproject/3` answers for `{px, py}`. A caller drawing a grid can take the map once and
add.

# `project`

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

Where world point `{x, y}` lands in the picture, in pixels from its top-left corner.

# `tile_at`

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

The tile under picture pixel `{px, py}`.

# `unproject`

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

The world point under picture pixel `{px, py}`, on the ground.

---

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