# `ExRatatui.ThreeD.Mesh`
[🔗](https://github.com/mcass19/ex_ratatui/blob/v0.13.0/lib/ex_ratatui/three_d/mesh.ex#L1)

Geometry for a 3D object: a built-in primitive or a custom triangle mesh.

Primitive meshes (`:cube`, `:sphere`, `:plane`) are built natively each frame
and carry no geometry data. Custom meshes carry their own vertices and triangle
indices; vertex normals are computed natively when omitted.

## Fields

  * `:kind` - `:cube`, `:sphere`, `:plane`, or `:custom`
  * `:stacks`, `:slices` - sphere tessellation (only for `:sphere`)
  * `:vertices` - list of `{x, y, z}` positions (only for `:custom`)
  * `:indices` - flat list of triangle indices, length a multiple of 3
    (only for `:custom`)
  * `:normals` - optional per-vertex `{x, y, z}` normals (only for `:custom`)
  * `:uvs` - optional per-vertex `{u, v}` texture coordinates (only for `:custom`)

Prefer the constructors over building the struct by hand.

## Examples

    iex> ExRatatui.ThreeD.Mesh.cube().kind
    :cube

    iex> sphere = ExRatatui.ThreeD.Mesh.sphere()
    iex> {sphere.kind, sphere.stacks, sphere.slices}
    {:sphere, 16, 24}

    iex> sphere = ExRatatui.ThreeD.Mesh.sphere(8, 12)
    iex> {sphere.kind, sphere.stacks, sphere.slices}
    {:sphere, 8, 12}

    iex> ExRatatui.ThreeD.Mesh.plane().kind
    :plane

    iex> mesh = ExRatatui.ThreeD.Mesh.new([{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}], [0, 1, 2])
    iex> {mesh.kind, mesh.indices}
    {:custom, [0, 1, 2]}

# `kind`

```elixir
@type kind() :: :cube | :sphere | :plane | :custom
```

# `t`

```elixir
@type t() :: %ExRatatui.ThreeD.Mesh{
  indices: [non_neg_integer()] | nil,
  kind: kind(),
  normals: [vec3()] | nil,
  slices: pos_integer() | nil,
  stacks: pos_integer() | nil,
  uvs: [{number(), number()}] | nil,
  vertices: [vec3()] | nil
}
```

# `vec3`

```elixir
@type vec3() :: {number(), number(), number()}
```

# `cube`

```elixir
@spec cube() :: t()
```

A unit cube centered at the origin.

# `cylinder`

```elixir
@spec cylinder(pos_integer()) :: t()
```

A unit cylinder: radius 0.5, height 1.0, axis +Y, centered at the origin.

`segments` is the number of radial subdivisions (minimum 3). Returns a custom
mesh (`kind: :custom`) with caps and per-vertex normals.

# `new`

```elixir
@spec new([vec3()], [non_neg_integer()], keyword()) :: t()
```

A custom triangle mesh from `vertices` and a flat list of triangle `indices`.

Options:

  * `:normals` - per-vertex normals; computed natively when omitted
  * `:uvs` - per-vertex texture coordinates

# `plane`

```elixir
@spec plane() :: t()
```

A unit plane in the XZ axis (normal +Y).

# `sphere`

```elixir
@spec sphere(pos_integer(), pos_integer()) :: t()
```

A unit sphere tessellated into `stacks` rings and `slices` segments.

---

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