lib/vivid.ex

defmodule Vivid do
  defmacro __using__(_opts) do
    quote do
      alias Vivid.{
        Arc,
        Bounds,
        Box,
        Buffer,
        Circle,
        Font,
        Font,
        Frame,
        Frame,
        Group,
        Group,
        Line,
        Path,
        Point,
        Polygon,
        Rasterize,
        RGBA,
        Transform
      }
    end
  end

  @moduledoc ~S"""
  Vivid is a 2D rendering engine implemented purely in Elixir.

  If you add `use Vivid` to your module then aliases for all the common Vivid
  modules will automatically be defined for you.

  ## Examples

    Drawing a box on the frame

      iex> use Vivid
      ...> frame = Frame.init(40, 20, RGBA.white)
      ...> box   = Box.init(Point.init(2,2), Point.init(12,12))
      ...> frame
      ...>   |> Frame.push(box, RGBA.black)
      ...>   |> to_string
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@           @@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@           @@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"

    And now add a circle.

      iex> use Vivid
      ...> frame  = Frame.init(40, 20, RGBA.white)
      ...> box    = Box.init(Point.init(2,2), Point.init(12,12))
      ...> circle = Circle.init(Point.init(20, 10), 5)
      ...> frame
      ...>   |> Frame.push(box, RGBA.black)
      ...>   |> Frame.push(circle, RGBA.init(0.5, 0.5, 0.5, 1))
      ...>   |> to_string
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@:::::@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@:@@@@@:@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@:@@@@@@@:@@@@@@@@@@@@@@@\n" <>
      "@@           @@@:@@@@@@@:@@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@:@@@@@@@@@:@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@:@@@@@@@@@:@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@:@@@@@@@@@:@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@:@@@@@@@:@@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@:@@@@@@@:@@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@:@@@@@:@@@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@@:::::@@@@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@           @@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"

    And now a triangle.

      iex> use Vivid
      ...> frame    = Frame.init(40, 20, RGBA.white)
      ...> box      = Box.init(Point.init(2,2), Point.init(12,12))
      ...> circle   = Circle.init(Point.init(20, 10), 5)
      ...> triangle = Circle.init(Point.init(30, 7), 5)
      ...>   |> Circle.to_polygon(3)
      ...> frame
      ...>   |> Frame.push(box, RGBA.black)
      ...>   |> Frame.push(circle, RGBA.init(0.5, 0.5, 0.5, 1))
      ...>   |> Frame.push(triangle, RGBA.init(0.8, 0.8, 0.8, 1))
      ...>   |> to_string
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@:::::@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@:@@@@@:@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@:@@@@@@@:@@@@@@@@@@@@@@@\n" <>
      "@@           @@@:@@@@@@@:@@@@@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@:@@@@@@@@@:@**@@@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@:@@@@@@@@@:@*@**@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@:@@@@@@@@@:@*@@@**@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@:@@@@@@@:@@*@@@@@**@@@@@\n" <>
      "@@ @@@@@@@@@ @@@:@@@@@@@:@@@*@@@@@@*@@@@\n" <>
      "@@ @@@@@@@@@ @@@@:@@@@@:@@@@*@@@@**@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@@:::::@@@@@*@@**@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@@@@@@@@@@@@***@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@@@@@@@@@@@@*@@@@@@@@@@@\n" <>
      "@@           @@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"

    And rotate the box.

      iex> use Vivid
      ...> frame    = Frame.init(40, 20, RGBA.white)
      ...> box      = Box.init(Point.init(2,2), Point.init(12,12))
      ...>   |> Transform.rotate(45)
      ...>   |> Transform.apply
      ...> circle   = Circle.init(Point.init(20, 10), 5)
      ...> triangle = Circle.init(Point.init(30, 7), 5)
      ...>   |> Circle.to_polygon(3)
      ...> frame
      ...>   |> Frame.push(box, RGBA.black)
      ...>   |> Frame.push(circle, RGBA.init(0.5, 0.5, 0.5, 1))
      ...>   |> Frame.push(triangle, RGBA.init(0.8, 0.8, 0.8, 1))
      ...>   |> to_string
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@@@:::::@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@ @@@@@@@@@:@@@@@:@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@ @ @@@@@@@:@@@@@@@:@@@@@@@@@@@@@@@\n" <>
      "@@@@@ @@@ @@@@@@:@@@@@@@:@@@@@@@@@@@@@@@\n" <>
      "@@@@ @@@@@ @@@@:@@@@@@@@@:@**@@@@@@@@@@@\n" <>
      "@@@ @@@@@@@ @@@:@@@@@@@@@:@*@**@@@@@@@@@\n" <>
      "@@ @@@@@@@@@ @@:@@@@@@@@@:@*@@@**@@@@@@@\n" <>
      "@ @@@@@@@@@@@ @@:@@@@@@@:@@*@@@@@**@@@@@\n" <>
      " @@@@@@@@@@@@@ @:@@@@@@@:@@@*@@@@@@*@@@@\n" <>
      "@ @@@@@@@@@@@ @@@:@@@@@:@@@@*@@@@**@@@@@\n" <>
      "@@ @@@@@@@@@ @@@@@:::::@@@@@*@@**@@@@@@@\n" <>
      "@@@ @@@@@@@ @@@@@@@@@@@@@@@@***@@@@@@@@@\n" <>
      "@@@@ @@@@@ @@@@@@@@@@@@@@@@@*@@@@@@@@@@@\n" <>
      "@@@@@ @@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"

    And apply a bunch of arbitrary transformations

      iex> use Vivid
      ...> frame    = Frame.init(40, 20, RGBA.white)
      ...> box      = Box.init(Point.init(2,2), Point.init(12,12))
      ...>   |> Transform.rotate(45)
      ...>   |> Transform.scale(0.75)
      ...>   |> Transform.translate(10, 10)
      ...>   |> Transform.apply
      ...> circle   = Circle.init(Point.init(20, 10), 5)
      ...>   |> Transform.fill(frame)
      ...>   |> Transform.center(frame)
      ...>   |> Transform.apply
      ...> triangle = Circle.init(Point.init(30, 7), 5)
      ...>   |> Circle.to_polygon(3)
      ...>   |> Transform.scale(1.5)
      ...>   |> Transform.apply
      ...> frame
      ...>   |> Frame.push(box, RGBA.black)
      ...>   |> Frame.push(circle, RGBA.init(0.5, 0.5, 0.5, 1))
      ...>   |> Frame.push(triangle, RGBA.init(0.8, 0.8, 0.8, 1))
      ...>   |> to_string
      "@@@@@@@@@@@@@@ @:::: :::@@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@ @:@@@@@ @@:@@@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@ ::@@@@@@@ @@::@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@: @@@@@@@ @@@@@:@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@:@@ @@@@@ @@@@@@@:@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@:@@@ @@@ @@@@@@@@:@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@:@@@@ @ @@@@@@@*@:@@@@@@@@@@@\n" <>
      "@@@@@@@@@@:@@@@@@ @@@@@@@@***:@@@@@@@@@@\n" <>
      "@@@@@@@@@@:@@@@@@@@@@@@@@@*@@:*@@@@@@@@@\n" <>
      "@@@@@@@@@@:@@@@@@@@@@@@@@@*@@:@**@@@@@@@\n" <>
      "@@@@@@@@@@:@@@@@@@@@@@@@@@*@@:@@@**@@@@@\n" <>
      "@@@@@@@@@@:@@@@@@@@@@@@@@@*@@:@@@@@**@@@\n" <>
      "@@@@@@@@@@@:@@@@@@@@@@@@@@*@:@@@@@@@@*@@\n" <>
      "@@@@@@@@@@@:@@@@@@@@@@@@@@*@:@@@@@@**@@@\n" <>
      "@@@@@@@@@@@:@@@@@@@@@@@@@@*@:@@@@**@@@@@\n" <>
      "@@@@@@@@@@@:@@@@@@@@@@@@@@*@:@@**@@@@@@@\n" <>
      "@@@@@@@@@@@@:@@@@@@@@@@@@@*:@**@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@::@@@@@@@@@@::**@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@:@@@@@@@@:@*@@@@@@@@@@@@@\n" <>
      "@@@@@@@@@@@@@@@@::::::::@@@@@@@@@@@@@@@@\n"
  """
end