https://github.com/erlangsters/opengl-4.6
OpenGL 4.6 binding for the BEAM (Erlang and Elixir).
https://github.com/erlangsters/opengl-4.6
binding elixir erlang erlangsters gl4 opengl
Last synced: about 2 months ago
JSON representation
OpenGL 4.6 binding for the BEAM (Erlang and Elixir).
- Host: GitHub
- URL: https://github.com/erlangsters/opengl-4.6
- Owner: erlangsters
- License: mit
- Created: 2024-09-24T16:50:31.000Z (almost 2 years ago)
- Default Branch: master
- Last Pushed: 2025-08-20T17:29:03.000Z (10 months ago)
- Last Synced: 2025-08-20T19:34:25.207Z (10 months ago)
- Topics: binding, elixir, erlang, erlangsters, gl4, opengl
- Language: Erlang
- Homepage: https://about.erlangsters.org
- Size: 217 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# OpenGL 4.6 binding for the BEAM
[](https://github.com/erlangsters/opengl-4.6)



[](https://github.com/erlangsters/opengl-4.6/actions/workflows/workflow.yml)
[](http://erlangsters.github.io/opengl-4.6/)
> [!WARNING]
> It's still in development and a first beta version will be available shortly.
> The master branch will be rewound!
This repository hosts the generated OpenGL 4.6 binding for the Erlang and
Elixir programming language. Only the core profile functions are exposed and
loading custom OpenGL functions is not supported.
```erlang
{ok, Version} = gl:get_string(version).
io:format("OpenGL version: ~p~n", [Version]).
```
```elixir
{:ok, version} = :gl.get_string(:version)
IO.puts("OpenGL version: #{version}")
```
It works exclusively with the [EGL binding](https://github.com/erlangsters/egl-1.5)
which will provide you with an OpenGL context and OpenGL surfaces to work with.
Additionally, you might want to use the [GLFW binding](https://github.com/erlangsters/glfw)
to provide you with a window.
> Bindings for other version of OpenGL and OpenGL ES are available. Visit the
> organization page of the Erlangsters community on Github to browse the list
> of [available bindings](https://github.com/orgs/erlangsters/repositories?type=all&q=opengl-).
Generated by the Erlangsters [community](https://about.erlangsters.org/) and
released under the MIT [license](https://opensource.org/license/mit).
## Quick preview
All the bits put together (EGL, OpenGL and some optional GLFW because it's
more fun with a window), here is how it looks like.
```erlang
Display = egl:get_display(default_display).
{ok, _} = egl:initialize(Display).
ConfigAttribs = [
{surface_type, [window_bit]},
{renderable_type, [opengl_bit]}
].
{ok, Configs} = egl:choose_config(Display, ConfigAttribs).
ContextAttribs = [
{context_major_version, 4},
{context_minor_version, 6}
],
egl:bind_api(opengl_api).
{ok, Context} = egl:create_context(Display, Config, no_context, ContextAttribs).
{ok, Window} = glfw:create_window(640, 480, "Hello World!").
WindowHandle = glfw:window_egl_handle(Window).
{ok, Surface} = egl:create_window_surface(Display, Config, WindowHandle, []).
ok = egl:make_current(Display, Surface, Surface, Context).
% Here goes your OpenGL initialization code...
Vertices = [
0.0, 0.5, 0.0, 1.0, 0.0, 0.0,
-0.5, -0.5, 0.0, 0.0, 1.0, 0.0,
0.5, -0.5, 0.0, 0.0, 0.0, 1.0
].
{ok, [Buffer]} = gl:gen_buffers(1),
gl:bind_buffer(array_buffer, Buffer),
gl:buffer_data(
array_buffer,
length(Vertices) * 4,
<<<> || Vertex <- Vertices>>,
static_draw
),
% ...
loop_window(Display, Surface, Window).
```
Here is how the loop function looks like.
```erlang
loop_window(Display, Surface, Window) ->
case glfw:window_should_close(Window) of
true ->
ok;
false ->
% Here goes your OpenGL rendering code...
gl:clear([color_buffer_bit]),
% ...
egl:swap_buffers(Display, Surface),
glfw:poll_events(Window),
handle_events(Window),
loop_window(Display, Surface, Window)
end.
```
Here is how the event handling function looks like.
```erlang
handle_events(Window) ->
receive
#glfw_window_size{size={Width, Height}} ->
gl:viewport(0, 0, Width, Height),
handle_events(Window)
after 0 ->
ok
end.
```
Fore more examples, consult the OpenGL samples [repository](https://github.com/erlangsters/opengl-samples)
which contains several mini-programs written in C, Erlang and Elixir.
## Working with the binding
To work with the binding, you will need to first hear about the "thread-safety"
implications (coming from the underlying C language) and how the API is
adjusted to match look and feel of the Erlang and Elixir languages.
**Thread-safety**
OpenGL is a C library that is not thread-safe -- each OpenGL function executes
in a OpenGL contexts bound to a single OS thread at a time. However, the BEAM
layers on top of OS threads (to provide the BEAM process primitive) and does
not expose them.
How does it work then ?
The thread-safety problem is solved by the EGL binding (hence its strong
dependency on it) and the solution is well-explained in its
[documentation](https://github.com/erlangsters/egl-1.5) (which you should consult).
However, here is a short version of the story: it works just like if a
BEAM process is equal to an OS thread.
If you think like this, all OpenGL code will work exactly like its counter-part
in C.
> Under the hood, the EGL binding executes the OpenGL calls in separate OS
> threads in a way that replicates the layout of the BEAM processes of your
> application.
**API mapping**
To make a low-level C API available in a higher-level Erlang/Elixir API, some
transformations are unavoidable. To remain highly consistent, it strictly
follows a set of mapping rules that are formally explained in the
[documentation](https://github.com/erlangsters/opengl-x.y-generator) of the
OpenGL binding generator.
Most of the time, you will be able to intuitively understand how a piece of
OpenGL code translates into its Erlang/Elixir counter-part. If not, the [API
reference](http://erlangsters.github.io/opengl-4.6/) from the generated
in-source documentation will clarify the rest.
## Using the binding in your project
With the **Rebar3** build system, add the following to the `rebar.config` file
of your project.
```
{deps, [
{egl, {git, "https://github.com/erlangsters/egl-1.5.git", {tag, "master"}}},
{gl, {git, "https://github.com/erlangsters/opengl-4.6.git", {tag, "master"}}}
]}.
```
If you happen to use the **Erlang.mk** build system, then add the following to
your Makefile.
```
BUILD_DEPS = egl gl
dep_egl = git https://github.com/erlangsters/egl-1.5 master
dep_gl = git https://github.com/erlangsters/opengl-4.6 master
```
In practice, you want to replace the branch "master" with a specific "tag" to
avoid breaking your project if incompatible changes are made.
## Generating the binding yourself
Like stated, this OpenGL binding is generated and the result is hosted in this
repo for convenience of use. However, you may want to be able to re-produce
the said result.
No problem, clone the
[OpenGL binding generator](https://github.com/erlangsters/opengl-x.y-generator)
repository, compile the generator and generate the binding.
```
rebar3 escriptize
./bin/opengl_gen gl 4.6
```
It produces the `gl.erl`, `gl.hrl` and `gl.c` that can be directly included in
your project. (Note that you'll need to configure your build system to produce '
a NIF library out of `gl.c`, of course.)