Skip to content

Commit

Permalink
Merge pull request #95 from ElixirSeattle/refactor/application-manage…
Browse files Browse the repository at this point in the history
…d-animations

Move animation management out of Engine
  • Loading branch information
vanvoljg authored Aug 1, 2020
2 parents 27056ff + ea6f45f commit 04f1645
Show file tree
Hide file tree
Showing 15 changed files with 206 additions and 176 deletions.
10 changes: 4 additions & 6 deletions lib/rgb_matrix/animation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ defmodule RGBMatrix.Animation do
}
defstruct [:type, :config, :state]

@callback new(leds :: [LED.t()], config :: Config.t()) :: {render_in, animation_state}
@callback new(leds :: [LED.t()], config :: Config.t()) :: animation_state
@callback render(state :: animation_state, config :: Config.t()) ::
{render_in, [RGBMatrix.any_color_model()], animation_state}
@callback interact(state :: animation_state, config :: Config.t(), led :: LED.t()) ::
Expand Down Expand Up @@ -59,19 +59,17 @@ defmodule RGBMatrix.Animation do
@doc """
Returns an animation's initial state.
"""
@spec new(animation_type :: type, leds :: [LED.t()]) :: {render_in, t}
@spec new(animation_type :: type, leds :: [LED.t()]) :: t
def new(animation_type, leds) do
config_module = Module.concat([animation_type, "Config"])
animation_config = config_module.new()
{render_in, animation_state} = animation_type.new(leds, animation_config)
animation_state = animation_type.new(leds, animation_config)

animation = %__MODULE__{
%__MODULE__{
type: animation_type,
config: animation_config,
state: animation_state
}

{render_in, animation}
end

@doc """
Expand Down
2 changes: 1 addition & 1 deletion lib/rgb_matrix/animation/breathing.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ defmodule RGBMatrix.Animation.Breathing do
def new(leds, _config) do
color = HSV.new(40, 100, 100)
led_ids = Enum.map(leds, & &1.id)
{0, %State{color: color, tick: 0, speed: 100, led_ids: led_ids}}
%State{color: color, tick: 0, speed: 100, led_ids: led_ids}
end

@impl true
Expand Down
2 changes: 1 addition & 1 deletion lib/rgb_matrix/animation/cycle_all.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ defmodule RGBMatrix.Animation.CycleAll do
@impl true
def new(leds, _config) do
led_ids = Enum.map(leds, & &1.id)
{0, %State{tick: 0, speed: 100, led_ids: led_ids}}
%State{tick: 0, speed: 100, led_ids: led_ids}
end

@impl true
Expand Down
2 changes: 1 addition & 1 deletion lib/rgb_matrix/animation/hue_wave.ex
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ defmodule RGBMatrix.Animation.HueWave do
@impl true
def new(leds, config) do
steps = 360 / config.width
{0, %State{tick: 0, leds: leds, steps: steps}}
%State{tick: 0, leds: leds, steps: steps}
end

@impl true
Expand Down
2 changes: 1 addition & 1 deletion lib/rgb_matrix/animation/pinwheel.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ defmodule RGBMatrix.Animation.Pinwheel do

@impl true
def new(leds, _config) do
{0, %State{tick: 0, speed: 100, leds: leds, center: determine_center(leds)}}
%State{tick: 0, speed: 100, leds: leds, center: determine_center(leds)}
end

defp determine_center(leds) do
Expand Down
11 changes: 5 additions & 6 deletions lib/rgb_matrix/animation/random_keypresses.ex
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,11 @@ defmodule RGBMatrix.Animation.RandomKeypresses do
def new(leds, _config) do
led_ids = Enum.map(leds, & &1.id)

{0,
%State{
led_ids: led_ids,
# NOTE: as to not conflict with possible led ID of `:all`
dirty: {:all}
}}
%State{
led_ids: led_ids,
# NOTE: as to not conflict with possible led ID of `:all`
dirty: {:all}
}
end

@impl true
Expand Down
2 changes: 1 addition & 1 deletion lib/rgb_matrix/animation/random_solid.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ defmodule RGBMatrix.Animation.RandomSolid do

@impl true
def new(leds, _config) do
{0, %State{led_ids: Enum.map(leds, & &1.id)}}
%State{led_ids: Enum.map(leds, & &1.id)}
end

@impl true
Expand Down
2 changes: 1 addition & 1 deletion lib/rgb_matrix/animation/solid_color.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ defmodule RGBMatrix.Animation.SolidColor do
@impl true
def new(leds, _config) do
color = HSV.new(120, 100, 100)
{0, %State{color: color, led_ids: Enum.map(leds, & &1.id)}}
%State{color: color, led_ids: Enum.map(leds, & &1.id)}
end

@impl true
Expand Down
2 changes: 1 addition & 1 deletion lib/rgb_matrix/animation/solid_reactive.ex
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ defmodule RGBMatrix.Animation.SolidReactive do
@impl true
def new(leds, _config) do
color = HSV.new(190, 100, 100)
{0, %State{first_render: true, paused: false, tick: 0, color: color, leds: leds, hits: %{}}}
%State{first_render: true, paused: false, tick: 0, color: color, leds: leds, hits: %{}}
end

@impl true
Expand Down
91 changes: 26 additions & 65 deletions lib/rgb_matrix/engine.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ defmodule RGBMatrix.Engine do
alias Layout.LED
alias RGBMatrix.Animation

@type frame :: %{LED.t() => RGBMatrix.any_color_model()}

defmodule State do
@moduledoc false
defstruct [:leds, :animation, :paintables, :last_frame, :timer, :configurables]
Expand All @@ -22,34 +24,31 @@ defmodule RGBMatrix.Engine do
This module registers its process globally and is expected to be started by a
supervisor.
This function accepts the following arguments as a tuple:
This function accepts the following argument:
- `leds` - The list of LEDs to be painted on.
- `initial_animation` - The Animation type to initialize and play when the
engine starts.
"""
@spec start_link({leds :: [LED.t()], initial_animation_type :: Animation.type()}) ::
GenServer.on_start()
def start_link({leds, initial_animation_type}) do
GenServer.start_link(__MODULE__, {leds, initial_animation_type}, name: __MODULE__)
@spec start_link(leds :: [LED.t()]) :: GenServer.on_start()
def start_link(leds) do
GenServer.start_link(__MODULE__, leds, name: __MODULE__)
end

@doc """
Sets the given animation as the currently active animation.
"""
@spec set_animation(animation_type :: Animation.type()) :: :ok
def set_animation(animation_type) do
GenServer.cast(__MODULE__, {:set_animation, animation_type})
@spec set_animation(animation :: Animation.t()) :: :ok
def set_animation(animation) do
GenServer.cast(__MODULE__, {:set_animation, animation})
end

@doc """
Register a paint function for the engine to send frames to.
This function is idempotent.
"""
@spec register_paintable(paint_fn :: function) :: {:ok, function}
@spec register_paintable(paint_fn :: function) :: {:ok, function, frame}
def register_paintable(paint_fn) do
:ok = GenServer.call(__MODULE__, {:register_paintable, paint_fn})
{:ok, paint_fn}
{:ok, frame} = GenServer.call(__MODULE__, {:register_paintable, paint_fn})
{:ok, paint_fn, frame}
end

@doc """
Expand All @@ -71,22 +70,6 @@ defmodule RGBMatrix.Engine do
GenServer.cast(__MODULE__, {:interact, led})
end

@doc """
Retrieves the current animation's configuration and configuration schema.
"""
@spec get_animation_config() :: {config :: any, config_schema :: any}
def get_animation_config do
GenServer.call(__MODULE__, :get_animation_config)
end

@doc """
Updates the current animation's configuration.
"""
@spec update_animation_config(params :: map) :: :ok | :error
def update_animation_config(params) do
GenServer.call(__MODULE__, {:update_animation_config, params})
end

@doc """
Register a config function for the engine to send animation configuration to
when it changes.
Expand All @@ -113,18 +96,16 @@ defmodule RGBMatrix.Engine do
# Server

@impl GenServer
def init({leds, initial_animation_type}) do
def init(leds) do
black = Chameleon.HSV.new(0, 0, 0)
frame = Map.new(leds, &{&1.id, black})

state =
%State{
leds: leds,
last_frame: frame,
paintables: MapSet.new(),
configurables: MapSet.new()
}
|> init_and_set_animation(initial_animation_type)
state = %State{
leds: leds,
last_frame: frame,
paintables: MapSet.new(),
configurables: MapSet.new()
}

{:ok, state}
end
Expand All @@ -139,14 +120,6 @@ defmodule RGBMatrix.Engine do
%State{state | paintables: paintables}
end

defp init_and_set_animation(state, animation_type) do
{render_in, animation} = Animation.new(animation_type, state.leds)

%State{state | animation: animation}
|> schedule_next_render(render_in)
|> inform_configurables()
end

defp schedule_next_render(state, :ignore) do
state
end
Expand Down Expand Up @@ -202,8 +175,12 @@ defmodule RGBMatrix.Engine do
end

@impl GenServer
def handle_cast({:set_animation, animation_type}, state) do
state = init_and_set_animation(state, animation_type)
def handle_cast({:set_animation, animation}, state) do
state =
%State{state | animation: animation}
|> schedule_next_render(0)
|> inform_configurables()

{:noreply, state}
end

Expand All @@ -221,7 +198,7 @@ defmodule RGBMatrix.Engine do
@impl GenServer
def handle_call({:register_paintable, paint_fn}, _from, state) do
state = add_paintable(paint_fn, state)
{:reply, :ok, state}
{:reply, {:ok, state.last_frame}, state}
end

@impl GenServer
Expand All @@ -230,22 +207,6 @@ defmodule RGBMatrix.Engine do
{:reply, :ok, state}
end

@impl GenServer
def handle_call(:get_animation_config, _from, state) do
{:reply, Animation.get_config(state.animation), state}
end

@impl GenServer
def handle_call({:update_animation_config, params}, _from, state) do
animation = Animation.update_config(state.animation, params)

state =
%State{state | animation: animation}
|> inform_configurables()

{:reply, :ok, state}
end

@impl GenServer
def handle_call({:register_configurable, config_fn}, _from, state) do
state = add_configurable(config_fn, state)
Expand Down
Loading

0 comments on commit 04f1645

Please sign in to comment.