Frame represents a collection of colours and shapes.
Frame implements both the Enumerable and Collectable protocols.
Examples
iex> use Vivid
...> Enum.map(1..5, fn i ->
...> line = Line.init(Point.init(1,1), Point.init(20, i * 4))
...> {line, RGBA.black}
...> end)
...> |> Enum.into(Frame.init(24, 21, RGBA.white))
...> |> to_string
"@@@@@@@@@@@@@@@@@@@@ @@@\n" <>
"@@@@@@@@@@@@@@@@@@@ @@@@\n" <>
"@@@@@@@@@@@@@@@@@@ @@@@@\n" <>
"@@@@@@@@@@@@@@@@@ @@@@@@\n" <>
"@@@@@@@@@@@@@@@@ @@@ @@@\n" <>
"@@@@@@@@@@@@@@@ @@@ @@@@\n" <>
"@@@@@@@@@@@@@@ @@ @@@@@\n" <>
"@@@@@@@@@@@@@ @@ @@@@@@@\n" <>
"@@@@@@@@@@@@ @@ @@@@ @@@\n" <>
"@@@@@@@@@@@ @@ @@@ @@@@\n" <>
"@@@@@@@@@@ @ @@ @@@@@@\n" <>
"@@@@@@@@@ @ @@ @@@@@@@@\n" <>
"@@@@@@@@ @ @@ @@@@@ @@@\n" <>
"@@@@@@@ @ @@@ @@@@@\n" <>
"@@@@@@ @ @@@ @@@@@@@@\n" <>
"@@@@@ @ @@ @@@@@@@@@@\n" <>
"@@@@ @@@@@@ @@@\n" <>
"@@@ @@@ @@@@@@@\n" <>
"@@ @@@@@@@@@@@@@\n" <>
"@ @@@@@@@@@@@@@@@@@@@\n" <>
"@@@@@@@@@@@@@@@@@@@@@@@@\n"
Summary
Functions
Return the background colour of the frame.
Change the background colour of the frame.
Render a frame into a buffer for display horizontally.
Render a frame into a buffer for display.
Clear the frame of any shapes.
Return the height of the frame.
Initialize a frame buffer.
Add a shape to the frame buffer.
Return how many samples per pixel, on each axis, the frame is rendered with.
Render the frame with samples samples per pixel on each axis.
Return the width of the frame.
Types
@type t() :: %Vivid.Frame{ background_colour: Vivid.RGBA.t(), height: pos_integer(), samples: pos_integer(), shapes: [{Vivid.Shape.t(), Vivid.RGBA.t()}], width: pos_integer() }
Functions
@spec background_colour(t()) :: Vivid.RGBA.t()
Return the background colour of the frame.
Example
iex> Vivid.Frame.init(80, 25) |> Vivid.Frame.background_colour
Vivid.RGBA.init(0, 0, 0, 0)
@spec background_colour(t(), Vivid.RGBA.t()) :: t()
Change the background colour of the frame.
Example
iex> Vivid.Frame.init(80,25)
...> |> Vivid.Frame.background_colour(Vivid.RGBA.white)
...> |> Vivid.Frame.background_colour
Vivid.RGBA.init(1, 1, 1, 1)
@spec buffer(t()) :: Vivid.Buffer.t()
Render a frame into a buffer for display horizontally.
Returns a one-dimensional List of RGBA colours with alpha-compositing
completed.
@spec buffer(t(), :horizontal | :vertical) :: Vivid.Buffer.t()
Render a frame into a buffer for display.
You can specify either :horizontal or :vertical mode, where in
:horizontal mode the buffer is rendered row-by-row then column-by-column
and in :vertical mode the buffer is rendered column-by-column then
row-by-row.
Returns a one-dimensional List of RGBA colours with alpha-compositing
completed.
Clear the frame of any shapes.
Return the height of the frame.
Example
iex> Vivid.Frame.init(80, 25) |> Vivid.Frame.height
25
@spec init(pos_integer(), pos_integer(), Vivid.RGBA.t()) :: t()
Initialize a frame buffer.
widththe width of the frame, in pixels.heightthe height of the frame, in pixels.colourthe default colour of the frame.
Example
iex> Vivid.Frame.init(4, 4)
Vivid.Frame.init(4, 4, Vivid.RGBA.init(0, 0, 0, 0))
@spec push(t(), Vivid.Shape.t(), Vivid.RGBA.t()) :: t()
Add a shape to the frame buffer.
frameis the frame to modify.shapeis the shape to add.colouris the colour of the shape being added.
Examples
iex> Vivid.Frame.init(5,5)
...> |> Vivid.Frame.push(Vivid.Line.init(Vivid.Point.init(1,1), Vivid.Point.init(3,3)), Vivid.RGBA.white)
...> |> to_string
" \n" <>
" @ \n" <>
" @ \n" <>
" @ \n" <>
" \n"
iex> Vivid.Frame.init(5,5)
...> |> Vivid.Frame.push(
...> Vivid.Path.init([
...> Vivid.Point.init(1,1),
...> Vivid.Point.init(1,3),
...> Vivid.Point.init(3,3),
...> Vivid.Point.init(3,1),
...> ]), Vivid.RGBA.white
...> )
...> |> to_string
" \n" <>
" @@@ \n" <>
" @ @ \n" <>
" @ @ \n" <>
" \n"
iex> Vivid.Frame.init(5,5)
...> |> Vivid.Frame.push(
...> Vivid.Polygon.init([
...> Vivid.Point.init(1,1),
...> Vivid.Point.init(1,3),
...> Vivid.Point.init(3,3),
...> Vivid.Point.init(3,1),
...> ]), Vivid.RGBA.white
...> )
...> |> to_string
" \n" <>
" @@@ \n" <>
" @ @ \n" <>
" @@@ \n" <>
" \n"
iex> circle = Vivid.Circle.init(Vivid.Point.init(5,5), 4)
...> Vivid.Frame.init(11, 10)
...> |> Vivid.Frame.push(circle, Vivid.RGBA.white)
...> |> to_string
" @@@ \n" <>
" @@ @@ \n" <>
" @ @ \n" <>
" @ @ \n" <>
" @ @ \n" <>
" @ @ \n" <>
" @ @ \n" <>
" @@ @@ \n" <>
" @@@ \n" <>
" \n"
iex> line = Vivid.Line.init(Vivid.Point.init(0,0), Vivid.Point.init(50,50))
...> Vivid.Frame.init(5,5)
...> |> Vivid.Frame.push(line, Vivid.RGBA.white)
...> |> to_string
" @\n" <>
" @ \n" <>
" @ \n" <>
" @ \n" <>
"@ \n"
@spec samples(t()) :: pos_integer()
Return how many samples per pixel, on each axis, the frame is rendered with.
Example
iex> Vivid.Frame.init(80, 25) |> Vivid.Frame.samples
1
@spec samples(t(), pos_integer()) :: t()
Render the frame with samples samples per pixel on each axis.
Shapes are rasterized at samples times the frame's size, and each pixel takes
its alpha from the proportion of its samples the shape covered. That's what
softens the stepping on any edge which isn't horizontal or vertical.
One sample per pixel - the default - is the aliased rendering this library has
always done, and costs nothing extra. Anything higher costs samples squared
as much rasterization, so 2 costs four times and 4 sixteen times.
Shapes which approximate a curve with straight lines - Vivid.Circle,
Vivid.Arc, Vivid.Bezier, and the glyphs of an outline font - choose how
finely to do that from their nominal size, before they know they're being
sampled. Sampling magnifies the line segments they already had rather than
smoothing them into a curve, so raise their step count too if the flat spots
show.
Examples
A diagonal line at the default one sample per pixel, stepping between rows.
iex> use Vivid
...> line = Line.init(Point.init(0, 0), Point.init(11, 5))
...> Frame.init(12, 6, RGBA.white())
...> |> Frame.push(line, RGBA.black())
...> |> to_string()
"@@@@@@@@@@ \n" <>
"@@@@@@@@ @@\n" <>
"@@@@@@ @@@@\n" <>
"@@@@ @@@@@@\n" <>
"@@ @@@@@@@@\n" <>
" @@@@@@@@@@\n"The same line with four samples per pixel. The ASCII renderer maps luminance onto ten characters, so partly covered pixels come out as the ones in between.
iex> use Vivid
...> line = Line.init(Point.init(0, 0), Point.init(11, 5))
...> Frame.init(12, 6, RGBA.white())
...> |> Frame.push(line, RGBA.black())
...> |> Frame.samples(4)
...> |> to_string()
"@@@@@@@@@@%%\n" <>
"@@@@@@@@%+*@\n" <>
"@@@@@@#+*@@@\n" <>
"@@@@*+#@@@@@\n" <>
"@@++%@@@@@@@\n" <>
"++@@@@@@@@@@\n"
Return the width of the frame.
Example
iex> Vivid.Frame.init(80, 25) |> Vivid.Frame.width
80