# `CauldronGPU.Bsp`
[🔗](https://github.com/jaman/cauldron/blob/v0.3.3/cauldron_gpu/lib/cauldron_gpu/bsp.ex#L2)

A `Cauldron3D.Bsp` world uploaded for drawing: one mesh per brush model, a material per
texture and lightmap page, the world's lightmaps packed into atlas pages.

    world = CauldronGPU.Bsp.upload(gpu, bsp, palette)
    CauldronGPU.submit(gpu, CauldronGPU.Bsp.instances(world, first_id: 1))

`models` holds the brush models that have faces to draw, in order; `model/2` finds one by
its number in the map (`*N` in an entity's model is number `N`).

Vertices stay in the map's own units and axes (+Z up); `transform/1` turns them into the
renderer's frame (+Y up) at `:scale` metres a unit, and `point/2` does the same for a
single point such as a spawn spot.

Texture kinds follow `Cauldron3D.Bsp`: `:solid` and `:masked` faces are lit by their
lightmaps (every light style, each scaled by `{:light_styles, …}`, times `:light_scale`), `:masked` texels of colour 255 are cut
out, `:sky` faces show the environment's sky (`sky_layers/3` gives a Quake world's),
`:liquid` faces are drawn unlit and rippling, `:hidden` faces are left out. In a
`:quake` world, palette colours 224 and up glow at full brightness.

Options:
  * `:scale` — metres per map unit, default `1 / 32`
  * `:light_scale` — lightmap multiplier, default `2.0`
  * `:filter` — texture filtering, `:linear` (default) or `:nearest`
  * `:page_size` — lightmap atlas page size in luxels, default `2048`

# `t`

```elixir
@type t() :: %CauldronGPU.Bsp{
  handles: [CauldronGPU.Handle.t()],
  models: [{CauldronGPU.Handle.t(), [CauldronGPU.Handle.t()]}],
  numbers: %{
    required(non_neg_integer()) =&gt;
      {CauldronGPU.Handle.t(), [CauldronGPU.Handle.t()]}
  },
  scale: number()
}
```

# `facing`

```elixir
@spec facing(number(), number()) :: CauldronGPU.Quat.t()
```

The camera rotation facing a map yaw of `degrees` (0 along +X, counter-clockwise from above).

# `instances`

```elixir
@spec instances(t(), keyword()) :: [CauldronGPU.Stream.change()]
```

Instance changes placing every brush model, ids counting up from `:first_id` (default 1).

# `light_style`

```elixir
@spec light_style(String.t(), number()) :: float()
```

The brightness at `seconds` of a light style written as a pattern of letters, `a`
dark to `z` brightest with `m` normal, stepping ten letters a second and repeating.

    CauldronGPU.Bsp.light_style("mmnmmommommnonmmonqnmmo", 2.35)

# `model`

```elixir
@spec model(t(), non_neg_integer()) ::
  {CauldronGPU.Handle.t(), [CauldronGPU.Handle.t()]} | nil
```

Brush model `number`'s mesh and materials, or `nil` when it has no faces to draw.

# `point`

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

A map point in the renderer's frame.

# `sky_layers`

```elixir
@spec sky_layers(CauldronGPU.Target.t(), Cauldron3D.Bsp.t(), binary()) ::
  {:layers, CauldronGPU.Handle.t(), CauldronGPU.Handle.t()} | nil
```

The sky picture of a `:quake` world, for `CauldronGPU.Environment`'s `sky_picture`:
its first `:sky` texture split into the back layer (the right half) and the front layer
(the left half, colour 0 see-through), uploaded through `target`. `nil` when the world
has no indexed sky texture. The caller keeps the two handles.

# `transform`

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

The transform that places map coordinates in the renderer's frame.

# `upload`

```elixir
@spec upload(CauldronGPU.Target.t(), Cauldron3D.Bsp.t(), binary(), keyword()) :: t()
```

Uploads `bsp`'s textures, lightmaps and brush models. `palette` is 768 bytes, used by textures without their own.

---

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