diff --git a/lib/vox/colour.ex b/lib/vox/colour.ex new file mode 100644 index 0000000..0a9ced4 --- /dev/null +++ b/lib/vox/colour.ex @@ -0,0 +1,5 @@ +defmodule Vox.Colour do + @type t :: %__MODULE__{ r: float, g: float, b: float, a: float } + + defstruct [r: 0.0, g: 0.0, b: 0.0, a: 1.0] +end diff --git a/lib/vox/material.ex b/lib/vox/material.ex new file mode 100644 index 0000000..9205850 --- /dev/null +++ b/lib/vox/material.ex @@ -0,0 +1,5 @@ +defmodule Vox.Material do + @type t :: %__MODULE__{ type: atom, properties: map } + + defstruct [type: :diffuse, properties: %{}] +end diff --git a/lib/vox/model.ex b/lib/vox/model.ex new file mode 100644 index 0000000..ba0a0c3 --- /dev/null +++ b/lib/vox/model.ex @@ -0,0 +1,55 @@ +defmodule Vox.Model do + @type bounds_error :: :bounds + @type unknown_error :: :unknown + @type error(type) :: { :error, { :model, type } } + + @type id :: non_neg_integer + @type axis :: non_neg_integer + @type point :: { axis, axis, axis } + + @type t :: %__MODULE__{ size: point, voxels: %{ point => Vox.Voxel.t } } + + defstruct [size: { 0, 0, 0 }, voxels: %{}] + + @spec width(t) :: axis + def width(%{ size: { w, _, _ } }), do: w + + @spec width(t) :: axis + def height(%{ size: { _, h, _ } }), do: h + + @spec width(t) :: axis + def depth(%{ size: { _, _, d } }), do: d + + @spec voxel(t, point) :: { :ok, Vox.Voxel.t | nil } | error(bounds_error) + def voxel(%{ size: { w, h, d } }, { x, y, z }) when (x < 0) or (x >= w) or (y < 0) or (y >= h) or (z < 0) or (z >= d), do: { :error, { :model, :bounds } } + def voxel(%{ voxels: voxels }, point), do: { :ok, voxels[point] } + + @spec voxel(t, axis, axis, axis) :: { :ok, Vox.Voxel.t | nil } | error(bounds_error) + def voxel(model, x, y, z), do: voxel(model, { x, y, z }) + + defmodule BoundsError do + defexception [:point, :model] + + @impl Exception + def exception({ model, point }) do + %BoundsError{ + point: point, + model: model + } + end + + @impl Exception + def message(%{ model: %{ size: size }, point: point }), do: "(#{inspect point}) outside of model's bounds: #{inspect size}" + end + + @spec voxel!(t, point) :: Vox.Voxel.t | nil | no_return + def voxel!(model, point) do + case voxel(model, point) do + { :ok, result } -> result + { :error, { :model, type } } -> raise BoundsError, { model, point } + end + end + + @spec voxel!(t, axis, axis, axis) :: Vox.Voxel.t | nil | no_return + def voxel!(model, x, y, z), do: voxel!(model, { x, y, z }) +end diff --git a/lib/vox/voxel.ex b/lib/vox/voxel.ex new file mode 100644 index 0000000..87e8874 --- /dev/null +++ b/lib/vox/voxel.ex @@ -0,0 +1,5 @@ +defmodule Vox.Voxel do + @type t :: %__MODULE__{ colour: Vox.Colour.t, material: Vox.Material.t } + + defstruct [colour: %Vox.Colour{}, material: %Vox.Material{}] +end