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

Samples a textured ground plane in perspective: for each pixel below the horizon the
world point it looks at, the tile there, and that tile's texel, faded towards a void
colour with distance.

    Cauldron2D.Projection.Ground.rows(%{
      grid: grid,
      size: {320, 200},
      tile: 16,
      camera: camera,
      void: {24, 30, 58},
      levels: 6,
      sky: sky
    })

A `grid` is the world made into data the sampler can read without calling back into
Elixir: `build_grid/3` turns a `fn {x, y} -> cell end` and a bounding box into one.

The work is done by a NIF where one built and in Elixir where it did not; `available?/0`
says which. The two answer the same picture but not always the same bytes: a pixel whose
world point falls within a last-bit rounding of a texel boundary may take the neighbouring
texel, so a handful of pixels a frame can differ, by one level of one channel. Where a
tile's texture is one colour the two are identical.

# `camera`

```elixir
@type camera() ::
  {float(), float(), float(), float(), float(), float(), float(), float(),
   float(), float(), float()}
```

# `grid`

```elixir
@type grid() :: %{
  cells: binary(),
  bounds: {pos_integer(), pos_integer(), integer(), integer()},
  textures: binary()
}
```

# `available?`

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

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

# `build_grid`

```elixir
@spec build_grid(
  ({integer(), integer()} -&gt; term()),
  {integer(), integer(), integer(), integer()},
  %{
    optional(term()) =&gt; pos_integer()
  }
) :: {binary(), {pos_integer(), pos_integer(), integer(), integer()}}
```

A grid of tile indices for `cell` over the box `{left, top, right, bottom}` in tiles,
with the textures the indices point at.

`arts` maps an art to its one-based index; a tile the map does not answer for, or whose
art is not in `arts`, is `0` and drawn as the void.

# `rows`

```elixir
@spec rows(map()) :: %{required(non_neg_integer()) =&gt; binary()}
```

The picture's rows as a map of row index to that row's pixels, the rows at and above
the horizon taken from `sky` and the rest sampled from the plane.

Takes `:grid`, `:size`, `:tile`, `:camera`, `:void`, `:levels` and `:sky`, where `sky`
is a tuple of one four-byte pixel per row. `native: false` samples in Elixir even where
the NIF loaded, which is how the two are checked against each other.

---

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