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

A Half-Life studio model (`Cauldron3D.Formats.Studio`) uploaded for drawing: one
skinned mesh in the model's rest pose, every vertex weighted wholly to its own bone,
one mesh part per skin reference, and its textures.

    {:ok, studio} = Cauldron3D.Formats.Studio.parse(File.read!("barney.mdl"))
    studio = Cauldron3D.Formats.Studio.add_textures(studio, File.read!("barneyt.mdl"))
    model = CauldronGPU.StudioModel.upload(gpu, studio)
    materials = CauldronGPU.StudioModel.materials(gpu, model)
    instance = CauldronGPU.StudioModel.instance(model, materials, CauldronGPU.Placement.transform(1 / 32, origin, 90))
    CauldronGPU.submit(gpu, [{:instance, 3, instance}, CauldronGPU.StudioModel.pose(model, 3, "walk", 0.8)])

Vertices stay in the model's own units and axes (x forward, y left, z up);
`CauldronGPU.Placement.transform/3` stands a model at a map point. Sequences that move
their motion bone along x, y or z have that movement taken out, so the model walks in
place and the caller moves the instance.

Texture flags are followed as far as the renderer's materials go: masked (`0x40`)
textures are cut out at colour 255, fullbright (`0x04`) ones are drawn unlit;
chrome and additive textures are drawn as plain textures.

# `t`

```elixir
@type t() :: %CauldronGPU.StudioModel{
  mesh: CauldronGPU.Handle.t(),
  skin_refs: [non_neg_integer()],
  studio: Cauldron3D.Formats.Studio.t(),
  textures: tuple(),
  unbind: tuple()
}
```

# `bones`

```elixir
@spec bones(t(), String.t() | non_neg_integer(), number(), keyword()) :: [
  CauldronGPU.Pose.matrix()
]
```

The bone matrices (3×4, row by row) posing the rest-pose mesh in `sequence` (a name,
without regard to case, or an index; an unknown one is sequence 0) at `time` seconds
into it, at the sequence's own frame rate. `opts` go to `Studio.locals/4`
(`:controllers`, `:subblend` and so on).

# `handles`

```elixir
@spec handles(t()) :: [CauldronGPU.Handle.t()]
```

Every handle the model holds.

# `instance`

```elixir
@spec instance(t(), [CauldronGPU.Handle.t()], CauldronGPU.Transform.t()) ::
  CauldronGPU.Instance.t()
```

An instance of the model with `materials` at `transform`.

# `materials`

```elixir
@spec materials(CauldronGPU.Target.t(), t(), keyword()) :: [CauldronGPU.Handle.t()]
```

One material per mesh part for skin family `:family` (default 0; a family the model
lacks is family 0). Options: `:lightmap`, a texture whose texel at lightmap
coordinates `{0, 0}` lights the whole model, times `:light_scale` (default 2.0).

# `pose`

```elixir
@spec pose(
  t(),
  CauldronGPU.Stream.id(),
  String.t() | non_neg_integer(),
  number(),
  keyword()
) ::
  CauldronGPU.Stream.change()
```

The `{:pose, id, …}` change for `bones/4`.

# `sequences`

```elixir
@spec sequences(t()) :: [String.t()]
```

The sequence names, in order.

# `upload`

```elixir
@spec upload(CauldronGPU.Target.t(), Cauldron3D.Formats.Studio.t(), keyword()) :: t()
```

Uploads `studio`'s textures and its mesh. Options: `:bodies`, a map from body part
index to the model index drawn for it (default 0 for each part), and `:filter`,
`:linear` (default) or `:nearest`. The textures must already be in `studio`
(`Studio.add_textures/2` for a model whose textures are in a separate file).

---

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