Current section

Files

Jump to
scenic lib utilities texture.ex
Raw

lib/utilities/texture.ex

#
# Created by Boyd Multerer on 2019-03-17.
# Copyright © 2019 Kry10 Industries. All rights reserved.
#
defmodule Scenic.Utilities.Texture do
alias Scenic.Primitive.Style.Paint.Color
@app Mix.Project.config()[:app]
# load the NIF
@compile {:autoload, false}
@on_load :load_nifs
@doc false
def load_nifs do
:ok =
@app
|> :code.priv_dir()
|> :filename.join('texture')
|> :erlang.load_nif(0)
end
# --------------------------------------------------------
# def build( :g, width, height, g ) when
# is_integer(g) and g >= 0 and g <= 255 and
# is_integer(width) and is_integer(height) and width > 0 and height > 0 do
# {:g, width, height, nif_pixels(width * height, g), []}
# end
def build(type, width, height, opts \\ [])
def build(:g, width, height, opts)
when is_integer(width) and is_integer(height) and width > 0 and height > 0 do
{g, opts} =
case opts[:clear] do
nil ->
{0, opts}
hint_clear ->
c = prep_clear(:g, hint_clear)
{c, Keyword.put(opts, :clear, c)}
end
case validate_channel(g, :invalid_clear) do
:ok -> {:ok, {:g, width, height, nif_pixels(width * height, g), opts}}
err -> err
end
end
# def build( :ga, width, height, {g,a} ) when
# is_integer(g) and g >= 0 and g <= 255 and
# is_integer(a) and a >= 0 and a <= 255 and
# is_integer(width) and is_integer(height) and width > 0 and height > 0 do
# {:ga, width, height, nif_pixels(width * height * 2, g, a), []}
# end
def build(:ga, width, height, opts)
when is_integer(width) and is_integer(height) and width > 0 and height > 0 do
{{g, a}, opts} =
case opts[:clear] do
nil ->
{{0, 0xFF}, opts}
hint_clear ->
c = prep_clear(:ga, hint_clear)
{c, Keyword.put(opts, :clear, c)}
end
with :ok <- validate_channel(g, :invalid_clear),
:ok <- validate_channel(a, :invalid_clear) do
{:ok, {:ga, width, height, nif_pixels(width * height * 2, g, a), opts}}
else
err -> err
end
end
# def build( :rgb, width, height, color ) when
# is_integer(width) and is_integer(height) and width > 0 and height > 0 do
# {r,g,b,_} = Color.to_rgba(color)
# {:rgb, width, height, nif_pixels(width * height * 3, r, g, b), []}
# end
def build(:rgb, width, height, opts)
when is_integer(width) and is_integer(height) and width > 0 and height > 0 do
{{r, g, b}, opts} =
case opts[:clear] do
nil ->
{{0, 0, 0}, opts}
hint_clear ->
c = prep_clear(:rgb, hint_clear)
{c, Keyword.put(opts, :clear, c)}
end
with :ok <- validate_channel(r, :invalid_clear),
:ok <- validate_channel(g, :invalid_clear),
:ok <- validate_channel(b, :invalid_clear) do
{:ok, {:rgb, width, height, nif_pixels(width * height * 3, r, g, b), opts}}
else
err -> err
end
end
def build(:rgba, width, height, opts)
when is_integer(width) and is_integer(height) and width > 0 and height > 0 do
{{r, g, b, a}, opts} =
case opts[:clear] do
nil ->
{{0, 0, 0, 0xFF}, opts}
hint_clear ->
c = prep_clear(:rgba, hint_clear)
{c, Keyword.put(opts, :clear, c)}
end
with :ok <- validate_channel(r, :invalid_clear),
:ok <- validate_channel(g, :invalid_clear),
:ok <- validate_channel(b, :invalid_clear),
:ok <- validate_channel(a, :invalid_clear) do
{:ok, {:rgba, width, height, nif_pixels(width * height * 4, r, g, b, a), opts}}
else
err -> err
end
end
defp validate_channel(v, err_type) do
with true <- is_integer(v),
true <- v >= 0,
true <- v <= 0xFF do
:ok
else
_ -> {:error, err_type}
end
end
defp nif_pixels(_, _), do: :erlang.nif_error("Did not find nif_pixels_g")
defp nif_pixels(_, _, _), do: :erlang.nif_error("Did not find nif_pixels_ga")
defp nif_pixels(_, _, _, _), do: :erlang.nif_error("Did not find nif_pixels_rgb")
defp nif_pixels(_, _, _, _, _), do: :erlang.nif_error("Did not find nif_pixels_rgba")
# --------------------------------------------------------
def build!(type, width, height, opts \\ []) do
{:ok, texture} = build(type, width, height, opts)
texture
end
# --------------------------------------------------------
def get(texture, x, y)
def get({:g, w, h, p, _}, x, y) when x >= 0 and x <= w and y >= 0 and y <= h,
do: nif_get_g(p, y * w + x)
def get({:ga, w, h, p, _}, x, y) when x >= 0 and x <= w and y >= 0 and y <= h,
do: nif_get_ga(p, y * w + x)
def get({:rgb, w, h, p, _}, x, y) when x >= 0 and x <= w and y >= 0 and y <= h,
do: nif_get_rgb(p, y * w + x)
def get({:rgba, w, h, p, _}, x, y) when x >= 0 and x <= w and y >= 0 and y <= h,
do: nif_get_rgba(p, y * w + x)
defp nif_get_g(_, _), do: :erlang.nif_error("Did not find nif_get_g")
defp nif_get_ga(_, _), do: :erlang.nif_error("Did not find nif_get_ga")
defp nif_get_rgb(_, _), do: :erlang.nif_error("Did not find nif_get_rgb")
defp nif_get_rgba(_, _), do: :erlang.nif_error("Did not find nif_get_rgba")
# --------------------------------------------------------
def put!(texture, x, y, color)
def put!({:g, w, h, p, hints}, x, y, color) when x >= 0 and x <= w and y >= 0 and y <= h do
g = prep_color(:g, color)
nif_put(p, y * w + x, g)
{:g, w, h, p, hints}
end
def put!({:ga, w, h, p, hints}, x, y, color) when x >= 0 and x <= w and y >= 0 and y <= h do
{g, a} = prep_color(:ga, color)
nif_put(p, y * w + x, g, a)
{:ga, w, h, p, hints}
end
def put!({:rgb, w, h, p, hints}, x, y, color) when x >= 0 and x <= w and y >= 0 and y <= h do
{r, g, b} = prep_color(:rgb, color)
nif_put(p, y * w + x, r, g, b)
{:rgb, w, h, p, hints}
end
def put!({:rgba, w, h, p, hints}, x, y, color) when x >= 0 and x <= w and y >= 0 and y <= h do
{r, g, b, a} = Color.to_rgba(color)
nif_put(p, y * w + x, r, g, b, a)
{:rgba, w, h, p, hints}
end
defp nif_put(_, _, _), do: :erlang.nif_error("Did not find nif_put_g")
defp nif_put(_, _, _, _), do: :erlang.nif_error("Did not find nif_put_ga")
defp nif_put(_, _, _, _, _), do: :erlang.nif_error("Did not find nif_put_rgb")
defp nif_put(_, _, _, _, _, _), do: :erlang.nif_error("Did not find nif_put_rgba")
# --------------------------------------------------------
def clear!(texture, color \\ nil)
def clear!({:g, w, h, p, hints}, color) do
g = prep_clear(:g, hints[:clear], color)
{:g, w, h, nif_clear(p, g), hints}
end
def clear!({:ga, w, h, p, hints}, color) do
{g, a} = prep_clear(:ga, hints[:clear], color)
{:ga, w, h, nif_clear(p, g, a), hints}
end
def clear!({:rgb, w, h, p, hints}, color) do
{r, g, b} = prep_clear(:rgb, hints[:clear], color)
{:rgb, w, h, nif_clear(p, r, g, b), hints}
end
def clear!({:rgba, w, h, p, hints}, color) do
{r, g, b, a} = prep_clear(:rgba, hints[:clear], color)
{:rgba, w, h, nif_clear(p, r, g, b, a), hints}
end
defp nif_clear(_, _), do: :erlang.nif_error("Did not find nif_clear_g")
defp nif_clear(_, _, _), do: :erlang.nif_error("Did not find nif_clear_ga")
defp nif_clear(_, _, _, _), do: :erlang.nif_error("Did not find nif_clear_rgb")
defp nif_clear(_, _, _, _, _), do: :erlang.nif_error("Did not find nif_clear_rgba")
# --------------------------------------------------------
def to_rgba(texture)
def to_rgba({:g, w, h, p, hints}) do
{:rgba, w, h, nif_g_to_rgba(p, w * h), hints}
end
def to_rgba({:ga, w, h, p, hints}) do
{:rgba, w, h, nif_ga_to_rgba(p, w * h), hints}
end
def to_rgba({:rgb, w, h, p, hints}) do
{:rgba, w, h, nif_rgb_to_rgba(p, w * h), hints}
end
def to_rgba({:rgba, _, _, _, _} = tex), do: tex
defp nif_g_to_rgba(_, _), do: :erlang.nif_error("Did not find nif_g_to_rgba")
defp nif_ga_to_rgba(_, _), do: :erlang.nif_error("Did not find nif_ga_to_rgba")
defp nif_rgb_to_rgba(_, _), do: :erlang.nif_error("Did not find nif_rgb_to_rgba")
# --------------------------------------------------------
defp prep_clear(type, hint_clear, color \\ nil)
defp prep_clear(type, hint_clear, color) do
prep_color(type, color || hint_clear || :black)
end
# --------------------------------------------------------
defp prep_color(type, color)
defp prep_color(:g, g) when is_integer(g), do: g
defp prep_color(:g, color) do
{r, g, b, _} = Color.to_rgba(color)
trunc((r + g + b) / 3)
end
defp prep_color(:ga, {g, a}) when is_integer(g) and is_integer(a), do: {g, a}
defp prep_color(:ga, color) do
{r, g, b, a} = Color.to_rgba(color)
{trunc((r + g + b) / 3), a}
end
defp prep_color(:rgb, {r, g, b})
when is_integer(r) and is_integer(g) and is_integer(b) do
{r, g, b}
end
defp prep_color(:rgb, color) do
{r, g, b, _} = Color.to_rgba(color)
{r, g, b}
end
defp prep_color(:rgba, color), do: Color.to_rgba(color)
end