# Uderzo
Uderzo is mostly an idea at the moment, a work in progress. Maybe some code will follow. Needless to
say, named after the Asterix creator, the half from the genius duo that made the images
(if I ever write a Elixir-based wordprocessor, it'll be called Goscinny. Promise).
The idea is to have an Elixir GUI in the following way:
* An executable that listens on an Erlang port and includes [NanoVG](https://github.com/memononen/nanovg)
* A library in Elixir that roughly replicates [NanoGUI](https://github.com/wjakob/nanogui)
The reason to separate the vector graphics and the GUI are multiple:
* With the OpenGL stuff in a separate executable, it can crash without taking down BEAM. Restart strategies are possible;
* The interesting bits are kept in Elixir and thus will be modifiable, etcetera. There's a ton of fun stuff you can do when your widget library is truly native and you have a code environment that's dynamic. See Morphic, Lively Kernel, etcetera.
* I'd like to abuse the opportunity to see whether the widgets can be generated by a DSL, pulling all the stops on macros and maybe some more advanced parsing as well.
Steps:
* [x] Build a basic wrapper executable
* [x] Open a window, show the NanoVG Demo
* [ ] Receive a mouseclick
* [ ] Lots and lots and lots of hard work to tie everything together.
# Setup
* Have a bunch of stuff installed. Use `make -f setup.mk (linux|mac)` to ensure that the
outide things are in place. The `linux` target is for Debian, so it might need tweaking
on other distributions. The `mac` target assumes homebrew is available.
* `mix deps.get`
* `mix compile`
* `mix test` should now briefly open a window with the first frame. If that works,
you can go to the next level:
* `iex -S mix` and run `Uderzo.Demo.run` from there.
Note: I'm doing nothing yet to make this work on non-linux envs, but also nothing to
make that hard. Nanovg is portable, and the wrapper executable should be minimal. It
already works on Linux OpenGL under Xorg and Broadcom's VideoCore.
# Protocol
To get started, we KISS and just use erlang term format. Later on we can have some hand-optimized
RPC going on.
Messages are fully async, so if you want a response, you need to send a pid to receive the
response along. By convention, we send that pid as the last argument on a call and
return responses as `{pid, response}` - the graphics genserver then simply dispatches
that with `send(pid, response)` and we're in Elixir-land from there.
We use the direct names of the GLFW/OpenGL/NanoVG libraries, uncamelcased. Pointers to
hold return values are converted to return tuples. E.g.
```c
double mx, my;
GLFWwindow *window;
glfwGetCursorPos(window, &mx, &my);
```
becomes
```elixir
glfw_get_cursor_pos(window, self())
receive do
{mx, my} -> ....
end
```
There is ample room for crashing the graphics server - pointers to windows, etcetera, are
directly returned as 64 bit numbers. As long as you just store and send them back as
opaque handles, everything is fine. If you don't, you will have spectacular crashes.
Note that crashing the graphics server should be fine: processes can monitor the
GenServer that will crash along, re-open the window, and simply resume the rendering
loop. With a bit of luck, it should be just a flicker.
TBD: Keyboard, mouse callbacks. These will be sent to pre-registered processes that
want them. On the other hand, for embedded setups, there's no thing like GLFW to do
this and a separate process to process input would be just fine.