# `CauldronGPU.Sectors.Live`
[🔗](https://github.com/jaman/cauldron/blob/v0.3.3/cauldron_gpu/lib/cauldron_gpu/sectors/live.ex#L2)

A `Cauldron2D.Sectors.Map` drawn while its sectors move: doors and lifts change
heights, lights flicker, switches and animated pictures change what sides and flats
show. Each sector is one mesh and one instance — its floors, ceilings and the walls
facing into it — and `update/5` rebuilds only the sectors that changed and their
neighbours. Each sector's light level is held in a lightmap with a row per sector
(`CauldronGPU.Sectors.Live.Lightmap`), put again whenever a light changes, and turned
into light falling with distance by a light table
(`CauldronGPU.Sectors.Live.LightTable`) the caller puts in its environment with
`light_space: :display`:

    {table, reach} = CauldronGPU.Sectors.Live.light_table(live)
    %CauldronGPU.Environment{light_space: :display, light_table: {table, reach}, tone_map: :clamp}

Sky ceilings and floors, and the upper walls left out between two sky ceilings, are
`sky` surfaces showing the environment's sky, so they hide what lies beyond them as
Doom's sky does; `sky_box/4` gives the sky picture as a box laid out as Doom draws its
sky (`CauldronGPU.Sectors.Live.SkyBox`), for the environment's `sky_picture`:

    {faces, live} = CauldronGPU.Sectors.Live.sky_box(live, target, 1.2, nil)
    %CauldronGPU.Environment{sky_picture: {:box, faces}}

    live = CauldronGPU.Sectors.Live.new(map, pictures, palette, sky: sky, sky_flats: [f_sky1], first_id: 1)
    {changes, live} = CauldronGPU.Sectors.Live.update(live, target, sectors, sides, shown: %{}, stretch: 1.2)
    CauldronGPU.Target.submit(target, changes)
    CauldronGPU.Target.submit(target, CauldronGPU.Sectors.Live.close(live, target))

`map` carries a BSP; `pictures` is the `Cauldron2D.Sectors.Pictures` set its picture
ids index, made with `native: false`; `palette` is 768 bytes. `sectors` and `sides` are
the map's as they are now, with the shapes `Cauldron2D.Sectors.Map` gives them.

Instances take the ids from `:first_id` up, one a sector in sector order (`ids/1`).

Options of `new/4`:
  * `:sky` — picture id of the sky, default none
  * `:sky_flats` — picture ids that mark a sky ceiling, default `[]`
  * `:first_id` — the first instance id, default `1`
  * `:scale` — metres per map unit, default `1 / 32`
  * `:light` — the options of `Cauldron2D.Sectors.Light` the light table follows,
    default `[]`

Options of `update/5`, as `Cauldron2D.Sectors.View` takes them:
  * `:shown` — `%{picture => picture}`, the picture drawn in place of another this
    tick, for animated pictures; default `%{}`
  * `:extra_light` — light added to every level, default `0`
  * `:fixed` — a light table every picture is drawn through at full light, default
    `nil`
  * `:stretch` — how many times taller than wide a map unit is drawn, default `1.0`

Pictures are uploaded the first time they are drawn.

# `t`

```elixir
@type t() :: %CauldronGPU.Sectors.Live{
  count: pos_integer(),
  first_id: pos_integer(),
  geometry: CauldronGPU.Sectors.Live.Geometry.t(),
  light: term(),
  light_options: keyword(),
  light_table: {CauldronGPU.Handle.t(), float()} | nil,
  lightmap: CauldronGPU.Handle.t() | nil,
  meshes: %{
    required(non_neg_integer()) =&gt; %{
      mesh: CauldronGPU.Handle.t(),
      keys: [term()]
    }
  },
  pictures: CauldronGPU.Sectors.Live.Pictures.t(),
  placed: %{required(non_neg_integer()) =&gt; term()},
  reach: float(),
  scale: number(),
  sectors: tuple() | nil,
  sides: tuple() | nil,
  sky: non_neg_integer() | nil,
  sky_boxes: %{
    required({number(), non_neg_integer() | nil}) =&gt; %{
      required(atom()) =&gt; CauldronGPU.Handle.t()
    }
  },
  sky_flats: MapSet.t(),
  sky_material: CauldronGPU.Handle.t() | nil
}
```

# `close`

```elixir
@spec close(t(), CauldronGPU.Target.t()) :: [CauldronGPU.Stream.change()]
```

Removes every instance placed and releases every handle uploaded; gives the removing changes.

# `far`

```elixir
@spec far(t(), number()) :: float()
```

A camera far distance, in the renderer's units, that keeps the level and its sky in view.

# `ids`

```elixir
@spec ids(t()) :: Range.t()
```

The instance ids the live map uses.

# `light_table`

```elixir
@spec light_table(t()) :: {CauldronGPU.Handle.t(), float()} | nil
```

The light table and its reach in metres, for the environment's `light_table`; `nil`
before the first `update/5`.

# `material`

```elixir
@spec material(
  t(),
  CauldronGPU.Target.t(),
  tuple(),
  (CauldronGPU.Sectors.Live.Pictures.texture() -&gt;
     CauldronGPU.Material.t())
) ::
  {CauldronGPU.Handle.t(), t()}
```

A material kept as `key` (a tuple whose second and third elements are a picture and a
light table), made the first time by `make` from that picture's texture.

# `new`

```elixir
@spec new(
  Cauldron2D.Sectors.Map.t(),
  Cauldron2D.Sectors.Pictures.t(),
  binary(),
  keyword()
) :: t()
```

A live map ready for its first `update/5`; nothing is uploaded yet.

# `point`

```elixir
@spec point(t(), {number(), number(), number()}, number()) ::
  {float(), float(), float()}
```

A map point `{x, y, height}` in the renderer's frame, heights times `stretch`.

# `sky_box`

```elixir
@spec sky_box(t(), CauldronGPU.Target.t(), number(), non_neg_integer() | nil) ::
  {%{required(atom()) =&gt; CauldronGPU.Handle.t()} | nil, t()}
```

The sky picture as the six faces of an environment's `{:box, faces}` sky, for heights
drawn `stretch` times taller than wide and pictures through light table `table`
(`nil` for none); made the first time for each, `nil` for a map with no sky picture.

# `texture`

```elixir
@spec texture(t(), CauldronGPU.Target.t(), non_neg_integer(), non_neg_integer() | nil) ::
  {CauldronGPU.Sectors.Live.Pictures.texture(), t()}
```

The texture of `picture` through light table `table` (`nil` for none), uploaded the first time.

# `transform`

```elixir
@spec transform(t(), number()) :: CauldronGPU.Transform.t()
```

The transform that places map coordinates in the renderer's frame, heights times `stretch`.

# `update`

```elixir
@spec update(t(), CauldronGPU.Target.t(), tuple(), tuple(), keyword()) ::
  {[CauldronGPU.Stream.change()], t()}
```

The changes that draw the map with `sectors` and `sides` as they are now, and the
live map to update next time. Meshes, textures and materials it needs are uploaded
through `target`.

---

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