glitter was an experimental library I made to attempt to codify the rules of OpenGL's state machine with Rust's type system. The goal was to have a zero-cost and safe wrapper around the OpenGL API, where invalid OpenGL calls would be caught at compile-time instead of runtime. The core idea is to represent OpenGL state using typestate.
I only got as far as wrapping a subset of OpenGL ES 2. While working on the project, I was held back by a number of Rust limitations, some of which have since been lifted (such as const generics), and others that still linger to this day (like partial borrowing).
Since I initially published glitter, the landscape of graphics APIs has evolved greatly, both in the Rust community and in the world at large. I no longer feel that glitter is a good fit for any kind of project-- gamedevs are better served by higher-level abstractions (like the renderer integrated in Bevy), engine devs are better served with platform-agnostic abstractions (like wgpu), and library devs are served better by direct access to graphics APIs without needing to jump through type-system hoops. Modern graphics APIs like Vulkan, Metal, and DX12 also seem to steer away from the stateful design of OpenGL, which makes something like glitter less compelling or interesting.
So, I've decided to put glitter into archive mode. I hope it will be of interest to those looking for inspiration in the future!
Note that this repo won't get any security patches! There are currently known security holes in some of the dependencies, so it should not be used for any serious projects!
There are some examples of glitter in the examples
directory, which use the sdl2
crate.
These can be run using cargo
, such as with the following:
$ cargo run --example hello-triangle
Also, just for a taste, here's a snippet for a simple "hello triangle" example:
#[macro_use] extern crate glitter;
use glitter::prelude::*;
// ...platform-specific OpenGL setup...
let gl = unsafe { glitter::Context::current_context() };
gl.clear_color(glitter::Color { r: 0.0, g: 0.0, b: 0.0, a: 0.0 });
gl.clear(glitter::COLOR_BUFFER_BIT);
#[derive(Clone, Copy)]
struct Vertex {
position: [f32; 2],
color: [f32; 3]
}
impl_vertex_data!(Vertex, position, color);
let vertices = [
Vertex { position: [-1.0, -1.0], color: [1.0, 0.0, 0.0] },
Vertex { position: [ 0.0, 1.0], color: [0.0, 1.0, 0.0] },
Vertex { position: [ 1.0, -1.0], color: [0.0, 0.0, 1.0] }
];
let vertex_source = r##"#version 100
attribute vec2 position;
attribute vec3 color;
varying vec3 _color;
void main() {
gl_Position = vec4(position, -1.0, -1.0);
_color = color;
}
"##;
let fragment_source = r##"#version 100
varying highp vec3 _color;
void main() {
gl_FragColor = vec4(_color, 1.0);
}
"##;
let vertex_shader = gl.build_vertex_shader(vertex_source).unwrap();
let fragment_shader = gl.build_fragment_shader(fragment_source).unwrap();
let mut program = gl.build_program(&[vertex_shader, fragment_shader]).unwrap();
let mut vertex_buffer: glitter::VertexBuffer<Vertex> = gl.new_vertex_buffer();
let attribs = attrib_pointers! {
position => gl.get_attrib_location(&program "position").unwrap(),
color => gl.get_attrib_location(&program, "color").unwrap()
};
vertex_buffer.bind_attrib_pointers(attribs);
let (mut gl_vertex_buffer, gl) = gl.bind_vertex_buffer(&mut vertex_buffer);
gl.buffer_vertices(&mut gl_vertex_buffer, &vertices, glitter::STATIC_DRAW);
let (_, gl) = gl.use_program(&mut program);
gl.draw_arrays_vbo(&gl_vertex_buffer, glitter::TRIANGLES);
glitter is designed to statically prevent OpenGL errors where possible, using compile-time checks. Additionally, in debug mode, glitter checks for all OpenGL errors by default.
Most OpenGL functions have a 1:1 parallel in glitter. Additionally,
a small set of higher-level abstractions are provided where applicable,
such as with the VertexBuffer
type, which provides a low-overhead, high-level interface for creating,
buffering, and drawing vertex data.
Many of the core types in glitter are composed of zero-sized types
or pointers to zero-sized types
(such as the Context
type). This means that glitter method calls can often compile directly OpenGL
function invocations.
For more details about how glitter achieves its design goals, consult the documentation.
All source code in this repository is licensed under both the MIT license
and the Apache 2.0 license, at the choice of the library user. All code in
the examples
directory is additionally available in the public domain, under the
terms of the Unlicense. See the appropriate LICENSE
files for some legal
words.