Packages
VElixir is a simple to use primitive 3D graphics library. It offers great performance, and ease of use. VElixir was inspired by VPython, which makes basic 3D graphics in python trivial. Now it's just as easy to make 3D graphical visualizations in Elixir.
Current section
Files
Jump to
Current section
Files
lib/velixir/render_looper.ex
defmodule VElixir.RenderLooper do
use GenServer
def start_link(args, opts \\ []) do
GenServer.start_link(__MODULE__, args, opts)
end
def init(args) do
cur_time = get_rel_seconds
state = %{
window: args.window,
c_server: args.c_server,
delay_millis: trunc(1000/Map.get(args.opts, :fps, 60)),
start_time: cur_time,
prev_time: cur_time,
opts: args.opts
}
send(self(), :render) #initiate the render loop
{:ok, state}
end
def handle_info(:render, state) do
render_start = get_rel_millis()
t = render_start / 1000.0
if Map.get(state.opts, :call_update, true), do: GenServer.cast(state.opts.render_source, {:update, t - state.prev_time, t - state.start_time})
render_objects = List.flatten(GenServer.call(state.opts.render_source, :render, 10_000))
mesh_map = VElixir.get_mesh_map(state.window)
render_data = VElixir.Misc.worker_map(render_objects, 10, fn obj ->
vtype = Map.get(obj, :vtype)
if !vtype, do: raise "Error, the following object cannot be rendered, because it is missing the property `:vtype`. #{inspect(obj)}"
vtype.export(obj, mesh_map)
end)
render_data = Enum.map(List.flatten(render_data), fn {id, matrix, color} -> [id, matrix, color] end)
send_transforms(state.c_server, render_data) #then send transform data
{:ok, "t"} = :enm.recv(state.c_server, 5_000) #wait for it to start
time_taken = get_rel_millis() - render_start
wait_time = trunc(state.delay_millis - time_taken)
wait_time = if wait_time < 0, do: 0, else: wait_time
:timer.send_after(wait_time, self(), :render) #call the render function again, after a delay
{:noreply, Map.put(state, :prev_time, t)}
end
defp send_transforms(c_server, transforms) do
VElixir.send_data(c_server, :transforms, transforms)
end
defp get_rel_millis do
:erlang.monotonic_time(:micro_seconds) / 1000.0
end
defp get_rel_seconds do
get_rel_millis / 1000.0
end
end