Skip to content

Commit c6cc754

Browse files
committed
lesson00 complete
1 parent 937611e commit c6cc754

File tree

12 files changed

+326
-10
lines changed

12 files changed

+326
-10
lines changed

.cargo/config

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[build]
2+
rustflags = ["-C","target-feature=+crt-static"]

.travis.yml

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
dist: xenial
2+
3+
os:
4+
- linux
5+
- osx
6+
7+
language: rust
8+
9+
rust:
10+
- stable
11+
12+
cache:
13+
cargo
14+
15+
branches:
16+
only:
17+
- staging
18+
- trying
19+
- master
20+
21+
before_script:
22+
- |
23+
if [[ $TRAVIS_OS_NAME == "linux" ]]; then \
24+
(test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update) && \
25+
(test -x $HOME/.cargo/bin/mdbook || cargo install mdbook) && \
26+
cargo install-update -a; \
27+
fi
28+
script:
29+
# builds all examples and builds+runs all tests
30+
- cargo test
31+
32+
# Also ensure that the book compiles right
33+
- mdbook build
34+
35+
# This deploy will push the mdbook output to the `ghpages` branch,
36+
# but you need to manually set up the GITHUB_TOKEN yourself for each
37+
# repo you make.
38+
39+
deploy:
40+
provider: pages
41+
local-dir: target/book-output
42+
skip-cleanup: true
43+
github-token: $GITHUB_TOKEN
44+
keep-history: false
45+
name: DocsBot
46+
verbose: true
47+
on:
48+
branch: master
49+
condition: $TRAVIS_OS_NAME = linux

Cargo.lock

+23-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+6-5
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
name = "learn-opengl"
33
description = "LearnOpenGL.com lessons in Rust"
44
repository = "https://github.com/Lokathor/learn-opengl"
5-
version = "0.1.0"
5+
version = "0.0.0"
66
authors = ["Lokathor <[email protected]>"]
77
edition = "2018"
88
license = "Zlib"
99

10-
publish = false
11-
1210
[dependencies]
1311
bytemuck = "1"
14-
imagine = "0.0.2"
15-
beryllium = "0.2.0-alpha.1"
1612
ogl33 = { version = "0.1", features = ["debug_error_checks", "debug_trace_messages"]}
13+
14+
[dev-dependencies]
15+
beryllium = "0.2.0-alpha.2"
16+
imagine = "0.0.2"
17+
ultraviolet = "0.3"

SDL2.dll

1.34 MB
Binary file not shown.

book-src/SUMMARY.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
# Learn OpenGL Rust
3+
4+
[Introduction](introduction.md)
5+
6+
* [Basics](basics/index.md)
7+
* [Creating A Window](basics/creating-a-window.md)

book-src/basics/creating-a-window.md

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Creating A Window
2+
3+
So, this part of the tutorial is very library specific, so I won't focus on it
4+
too much.
5+
6+
Basically, we have to open a window, and we also need a GL context to go with that window.
7+
8+
On most platforms, you have to specify that you'll be using GL _before_ you create the window, so that the window itself can be created with the correct settings to support GL once it's made.
9+
10+
In our case, first we turn on SDL itself:
11+
12+
```rust
13+
use beryllium::*;
14+
15+
fn main() {
16+
let sdl = SDL::init(InitFlags::Everything).expect("couldn't start SDL");
17+
```
18+
19+
Then we set some GL attributes that we want to use:
20+
21+
```rust
22+
sdl.gl_set_attribute(SdlGlAttr::MajorVersion, 3).unwrap();
23+
sdl.gl_set_attribute(SdlGlAttr::MinorVersion, 3).unwrap();
24+
sdl.gl_set_attribute(SdlGlAttr::Profile, GlProfile::Core).unwrap();
25+
sdl
26+
.gl_set_attribute(SdlGlAttr::Flags, ContextFlag::ForwardCompatible)
27+
.unwrap();
28+
```
29+
30+
Finally we can make our window.
31+
32+
```rust
33+
let _win = sdl
34+
.create_gl_window(
35+
"Hello Window",
36+
WindowPosition::Centered,
37+
800,
38+
600,
39+
WindowFlags::Shown,
40+
)
41+
.expect("couldn't make a window and context");
42+
```
43+
44+
Once we have a window, we can poll for events. Right now we just wait for a quit
45+
event (user clicked the X on the window, pressed Alt+F4, etc) and then quit when
46+
that happens.
47+
48+
```rust
49+
'main_loop: loop {
50+
while let Some(event) = sdl.poll_events().and_then(Result::ok) {
51+
// handle events this frame
52+
match event {
53+
Event::Quit(_) => break 'main_loop,
54+
_ => (),
55+
}
56+
57+
// here's where we could change the world state and draw.
58+
}
59+
}
60+
}
61+
```
62+
63+
That's all there is to it. Just a milk run.
64+
65+
## Extras
66+
67+
I'm developing mostly on Windows, and Windows is where most of your market share of users will end up being, so here's some bonus Windows tips:
68+
69+
### Windows Subsystem
70+
71+
I'm going to put the following attribute at the top of the file:
72+
73+
```rust
74+
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
75+
```
76+
77+
This will make is to that a "release" build (with the `--release` flag) will use the "windows" subsystem on Windows, instead of the "console" subsystem. This makes the process not have a console by default, which prevents a little terminal window from running in the background when the program runs on its own. However, we only want that in release mode because we want the ability to print debug message in debug mode.
78+
79+
### Static C Runtime
80+
81+
Also, I'm going to add a `.cargo/` folder to the project and put a `config` file inside.
82+
83+
```toml
84+
[build]
85+
rustflags = ["-C","target-feature=+crt-static"]
86+
```
87+
88+
This will make Rust compile in a static C runtime when it builds the binaries, so that the binaries can be sent to others without them needing to have the MSVC redistributable DLLs or other files like that on their machine. It's not on by default because I don't even know why. I think it makes programs marginally larger, but it doesn't seem to make them compile slower so whatever.
89+
90+
We could instead make a totally `no_std` program if we wanted to, but that's a whole set of steps and not really OpenGL related at all, so for this tutorial book we'll use the "quick and dirty" way to get our programs to be easily portable.
91+
92+
### Static Linking SDL2
93+
94+
Finally, instead of dynamic linking with SDL2 we could static link with it.
95+
96+
All we have to static link SDL2 instead is change our Cargo.toml file so that instead of saying
97+
98+
```toml
99+
beryllium = "0.2.0-alpha.2"
100+
```
101+
102+
it says
103+
104+
```toml
105+
beryllium = { version = "0.2.0-alpha.1", default-features = false, features = ["link_static"] }
106+
```
107+
108+
However, when we do this, we have to build the SDL2 static lib, which takes longer (about +30 seconds). So I leave it in dynamic link during development because it makes CI go faster.

book-src/basics/index.md

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Basics
2+
3+
TODO: maybe some of this can go into the Introduction. whatever.
4+
5+
It's become the "older" style among the graphics APIs, with Vulkan / DX12 / Metal being the new hotness.
6+
7+
However, I think that it's easy enough to use and you don't often need the final ounce of performance that you can get with Vulkan.
8+
9+
We'll be using OpenGL 3.3. The latest version is 4.6, but we'll be using 3.3. The main reason for this is because if we take a quick look at Mac's [supported OpenGL versions](https://support.apple.com/en-us/HT202823) we can see that they support 3.3 on old stuff and 4.1 on new 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.
10+
11+
OpenGL is a _specification_, and it's a specification for a C API. It's probably implemented in C as well, but actually you could implement it in any language that can expose a C API. Time to rewrite OGL in Rust, ne?
12+
13+
So we'll be doing a lot of FFI calls. FFI calls are naturally `unsafe`. If you're not comfortable with that then go use [glium](https://docs.rs/glium), or [wgpu](https://docs.rs/wgpu) or something. Phaazon converted their [luminance tutorial](https://github.com/rust-tutorials/learn-luminance) into a more bookish form recently too. You don't _have_ to use OpenGL directly.
14+
15+
But if you want to know how people _built_ those other libraries, you gotta learn this direct usage stuff.
16+
17+
## Prior Knowledge
18+
19+
You should generally be familiar with all the topics covered in [The Rust
20+
Programming Language](https://doc.rust-lang.org/book/), but you don't need to
21+
have them memorized you can look things up again if you need to.
22+
23+
I usually tell folks that they should read [The
24+
Rustonomicon](https://doc.rust-lang.org/nomicon/) before doing a lot of unsafe
25+
code. However, with GL you're not really doing a lot of hackery _within Rust_
26+
that could go wrong. It's just that the driver could explode in your face if you
27+
look at it funny. Or even if you don't, because drivers are just buggy
28+
sometimes. Oh well, that's life.
29+
30+
## Libraries Used
31+
32+
As I start this project, this is what my Cargo.toml looks like.
33+
34+
```toml
35+
[dependencies]
36+
bytemuck = "1"
37+
ogl33 = { version = "0.1", features = ["debug_error_checks", "debug_trace_messages"]}
38+
39+
[dev-dependencies]
40+
beryllium = "0.2.0-alpha.2"
41+
imagine = "0.0.2"
42+
ultraviolet = "0.3"
43+
```
44+
45+
So the library itself, where we'll put our useful GL helpers, will depend on
46+
47+
* [ogl33](https://docs.rs/ogl33), which gives us bindings to OpenGL.
48+
* It works mostly like the [gl](https://docs.rs/gl) crate, except it _only_
49+
connects to OpenGL 3.3 (the `gl` crate builds for 4.6).
50+
* [bytemuck](https://docs.rs/bytemuck), which is a handy crate for casting around data types.
51+
52+
And then if you're not familiar with "dev-dependencies", that's bonus dependencies that tests and examples can use. Since our example programs will be examples, they can use extra things that aren't critical to 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.
53+
54+
* [beryllium](https://docs.rs/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.
55+
* Other options: [winit](https://docs.rs/winit), [glfw](https://docs.rs/glfw)
56+
* [imagine](https://docs.rs/imagine) is a PNG parser (not used right away, but soon enough).
57+
* Other options: [image](https://docs.rs/image), which uses [png](https://docs.rs/png)
58+
* [ultraviolet](https://docs.rs/ultraviolet) is a graphics linear algebra crate.
59+
* Other options: [glam](https://docs.rs/glam), [nalgebra-glm](https://docs.rs/nalgebra-glm)
60+
61+
Full disclosure: I wrote almost all of the crates on the list. Other than
62+
`ultraviolet`, which was done by [Fusha](https://github.com/termhn), because I'm
63+
a dummy who can't do math.
64+
65+
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.

book-src/introduction.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Introduction
2+
3+
This is a book, well, "book", about learning OpenGL usage with Rust.
4+
5+
It's based on [learnopengl.com](https://learnopengl.com/), which is for C++.
6+
7+
It's about OpenGL (OGL), which is one particular flavor of GL within the larger
8+
GL family. There's also OpenGL ES (GLES), which is for embedded systems like
9+
phones and raspberry pi, and there's WebGL which is for GL in the browser.
10+
11+
I don't expect that I will write all the lesson text well enough
12+
in the first draft for it to be a stand alone teaching method.
13+
14+
However, the code itself will compile and work of course, so if you
15+
look at the code and read the pages here and the pages there it'll hopefully
16+
make some sense when you add it all up.
17+
18+
Sorry, but books like this are kinda difficult to write properly,
19+
and I want to put more focus on getting out working examples than on
20+
having perfect tutorial text.

book.toml

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[book]
2+
title = "Learn OpenGL Rust"
3+
authors = ["Lokathor"]
4+
description = "A version of the LearnOpenGL book for Rust."
5+
src = "book-src"
6+
language = "en"
7+
8+
[build]
9+
build-dir = "target/book-output"
10+
create-missing = true

examples/hello-window.rs

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
2+
#![allow(clippy::single_match)]
3+
4+
use beryllium::*;
5+
6+
fn main() {
7+
let sdl = SDL::init(InitFlags::Everything).expect("couldn't start SDL");
8+
sdl.gl_set_attribute(SdlGlAttr::MajorVersion, 3).unwrap();
9+
sdl.gl_set_attribute(SdlGlAttr::MinorVersion, 3).unwrap();
10+
sdl.gl_set_attribute(SdlGlAttr::Profile, GlProfile::Core).unwrap();
11+
sdl
12+
.gl_set_attribute(SdlGlAttr::Flags, ContextFlag::ForwardCompatible)
13+
.unwrap();
14+
15+
let _win = sdl
16+
.create_gl_window(
17+
"Hello Window",
18+
WindowPosition::Centered,
19+
800,
20+
600,
21+
WindowFlags::Shown,
22+
)
23+
.expect("couldn't make a window and context");
24+
25+
'main_loop: loop {
26+
while let Some(event) = sdl.poll_events().and_then(Result::ok) {
27+
// handle events this frame
28+
match event {
29+
Event::Quit(_) => break 'main_loop,
30+
_ => (),
31+
}
32+
33+
// here's where we could change the world state and draw.
34+
}
35+
}
36+
}

src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
21
//

0 commit comments

Comments
 (0)