https://github.com/gregtatum/rugl
I've been working on a side project to build a clone of my favorite WebGL framework regl in Rust. It seemed like a nice problem to work through. I've finally got it to the point where it's actually moving things across the screen.
This tweet has a video of the triangles moving:
https://twitter.com/TatumCreative/status/862836748593790976
And this is what the API looks like so far for creating the draw call:
extern crate rugl;
fn main() {
let mut rugl = rugl::init();
let count = 1000;
let draw = rugl.draw()
.vert("
#version 150
in vec2 position;
in float id;
uniform float time;
uniform float count;
float TRIANGLE_SIZE = 0.02;
void main() {
float unit_id = id / count;
vec2 offset = vec2(
2.0 * (unit_id - 0.5) + 0.1 * sin(unit_id * 30.0 + time * 2.5) + 0.5 * sin(unit_id * 50.0 + time * 5.234),
(sin(unit_id * 20.0 + time) + sin(unit_id * 7.0 + time * 2.83)) / 3.0 + 0.5 * sin(unit_id * 66.0 + time * 7.234)
);
gl_Position = vec4(
position * TRIANGLE_SIZE + offset,
0.0,
1.0
);
}
")
.frag("
#version 150
out vec4 out_color;
void main() {
out_color = vec4(1.0, 1.0, 1.0, 1.0);
}
")
.uniform("time", Box::new(|env| Box::new(env.time as f32)))
.uniform("count", {
let count_in = count.clone() as f32;
Box::new(move |env| Box::new(count_in))
})
.attribute("position", {
&((0..(count * 3)).map(|i| {
// Equilateral triangle
match i % 3 {
0 => [0.0, 0.5],
1 => [0.36056, -0.5],
2 => [-0.36056, -0.5],
_ => panic!("Math is hard.")
}
}).collect::<Vec<[f32; 2]>>())
})
.attribute("id", {
&((0..(count * 3)).map(|i| {
(i as f32 / 3.0).floor()
}).collect::<Vec<f32>>())
})
.count(count * 3)
.finalize();
rugl.frame(|env| {
draw(env);
});
}
So far the experience in Rust has been interesting. The biggest challenges have been dealing with generics and traits for polymorphic methods. I come from more of a dynamic language background, so dealing with code at the systems level has been a nice challenge. There are quite a few unsafe blocks dealing with the gl-side of things, so I had to spend a lot of time working on understanding how Rust lays things out in memory.
Next steps will be to add more support for different data types on uniforms and attributes, and maybe try to write a few macros to cut down on the verbosity of some of the draw calls. Testing seems like an interesting problem to solve as well.