Basics
TODO: maybe some of this can go into the Introduction? whatever.
We'll be using OpenGL 3.3. The latest version is 4.6, but we'll still be using 3.3. The main reason for this is because if we take a quick look at Mac's supported OpenGL versions we can see that they support 3.3 on older stuff and 4.1 on newer stuff. Macs don't get OpenGL 4.6 like Windows and Linux have. Oh well. Feel free to use this book and then learn the stuff that got added after 3.3 if you don't care about supporting old macs.
OpenGL is a specification. Not a specific implementation, just a specification. Each graphics card has its own driver, which has its own implementation of OpenGL. This means that you can run in to bugs on one card that doesn't show up on other cards. Fun!
OpenGL is specified in terms of a series of C functions that you can call. They all affect a "Context". A GL context has all sorts of state inside. There's GL calls to draw things, but there's also a lot of calls to carefully set the state before the drawing happens. Both types of call are equally important to getting a picture on the screen.
So we'll be doing a lot of FFI calls. FFI calls are naturally unsafe
,
because the Rust compiler can't see what's going on over there.
If you don't want to have to call unsafe
code you can try
luminance, or
glium, or wgpu or, something
like that. You don't have to call unsafe
code to get a picture on the
screen.
But if you want to know how people built those other libraries that let you do those cool things, you gotta learn this direct usage stuff.
Prior Knowledge
You should generally be familiar with all the topics covered in The Rust Programming Language, but you don't need to have them memorized. You can look things up again if you need to.
I usually tell folks that they should read The Rustonomicon before doing a lot of unsafe code. However, with GL you're not really doing a lot of hackery within Rust that could go wrong. It's just that the driver could explode in your face if you look at it funny. Or even if you don't, because drivers are just buggy sometimes. Oh well, that's life.
Libraries Used
As I start this project, this is what my Cargo.toml looks like.
[dependencies]
bytemuck = "1"
ogl33 = { version = "0.2.0", features = ["debug_error_checks"]}
[dev-dependencies]
beryllium = "0.2.0-alpha.4"
imagine = "0.0.5"
So the library itself, where we'll put our useful GL helpers, will depend on
- ogl33, which gives us bindings to OpenGL.
- It's similar to the gl crate (which loads OpenGL 4.6), but all functions and constants use their real names exactly as you'd see in C code. It makes it a lot easier to read books and blogs about OpenGL that are written for C (which is essentially all of them), and then quickly translate it to Rust.
- bytemuck, which is a handy crate for casting around plain data types.
And then if you're not familiar with "dev-dependencies", that's bonus
dependencies that tests and examples can use (but not bins!). Since our example
programs will be examples in the examples/
directory, they'll be able to use
"dev-dependencies" without that affecting the lib itself. That way if someone
else wants to use the lib they can use just the lib in their own program,
without having to also build the stuff we're using for our examples.
- beryllium is an SDL2 wrapper. It will dynamic
link by default so you'll need
SDL2.dll
in your path to run a program. You can swap this to static linking, I describe that at the end of the first lesson. - imagine is a PNG parser (not used right away, but soon enough).
- ultraviolet is a graphics linear algebra crate.
- Other options: glam, nalgebra-glm
Full disclosure: I wrote almost all of the crates on the list. Other than
ultraviolet
, which was done by Fusha, because I'm
a dummy who can't do math.
However, I'm writing the book, so I get to use my own crates while I do it. I think this is fair, and I'm also providing alternative suggestions for each one, so I don't feel bad about it.