Skip to content

Commit f2d26de

Browse files
committed
lesson 003
1 parent 7e25eac commit f2d26de

File tree

4 files changed

+141
-2
lines changed

4 files changed

+141
-2
lines changed

book-src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* [Creating A Window](basics/000-creating-a-window.md)
88
* [Drawing A Triangle](basics/001-drawing-a-triangle.md)
99
* [Triangle Cleanup](basics/002-triangle-cleanup.md)
10+
* [Rectangle Elements](basics/003-rectangle.md)
1011
* [Appendix: Math](appendix-math/index.md)
1112
* [Vectors](appendix-math/vectors.md)
1213
* [Matrices](appendix-math/matrices.md)

book-src/basics/003-rectangle.md

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# Rectangle Elements
2+
3+
Naturally we don't want just one triangle. When you're playing The Witcher 3,
4+
there's at least two triangles on the screen (maybe more!).
5+
6+
Let's move on to drawing a rectangle. For this we need a second triangle.
7+
8+
We could just add three more vertex entries and call it a day. If we wanted two
9+
triangles that were each on their own that's what we might do. However, since
10+
these two triangles making up our rectangle are going to be directly touching,
11+
that means we'd have six vertexes making up only four "real" points. That's 50%
12+
more space used than we want! It may seem small now, but a complete model for a
13+
tree or a person or something like that can easily end up being thousands of
14+
triangles. Making that be 50% more space used is a bad time.
15+
16+
Of course this problem of duplicate vertices is a fairly easy problem to solve,
17+
and GL has it covered. What we do is specify an [Index
18+
Buffer](https://www.khronos.org/opengl/wiki/Vertex_Specification#Index_buffers).
19+
It holds the indexes of the vertex buffer entries we want to use to form each
20+
geometry element (in this case triangles). Then the vertex buffer doesn't need
21+
to have any duplicates, we just have more than one triangle index the same
22+
vertex.
23+
24+
Note: What we'll be drawing is usually called a "quad", because the important
25+
part is that it has four outside edges. It's not really important that the edges
26+
are in two pairs of parallel lines at right angles with each other like a true
27+
rectangle has.
28+
29+
## Data
30+
31+
So we've got some new data. We're going to have 4 vertex entries that describes
32+
the points we want to use, and an index buffer with 2 entries where each entry
33+
describes a triangle using the points.
34+
35+
```rust
36+
type Vertex = [f32; 3];
37+
type TriIndexes = [u32; 3];
38+
39+
const VERTICES: [Vertex; 4] =
40+
[[0.5, 0.5, 0.0], [0.5, -0.5, 0.0], [-0.5, -0.5, 0.0], [-0.5, 0.5, 0.0]];
41+
42+
const INDICES: [TriIndexes; 2] = [[0, 1, 3], [1, 2, 3]];
43+
```
44+
45+
## Element Buffer Object
46+
47+
Our indexes go into a separate kind of buffer. This is that `ElementArray`
48+
buffer type that I snuck into the cleanup lesson.
49+
50+
After we make and bind our vertex data we also bind a buffer for the element
51+
data and upload it, the code looks nearly identical:
52+
53+
```rust
54+
let ebo = Buffer::new().expect("Couldn't make the element buffer.");
55+
ebo.bind(BufferType::ElementArray);
56+
learn::buffer_data(
57+
BufferType::ElementArray,
58+
bytemuck::cast_slice(&INDICES),
59+
GL_STATIC_DRAW,
60+
);
61+
```
62+
63+
## Draw It!
64+
65+
Finally, instead of calling `glDrawArrays`, we use a separate function called [`glDrawElements`](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glDrawElements.xhtml).
66+
67+
* `mode`: The style of drawing. We're still drawing triangles so we keep that
68+
from before.
69+
* `count`: The number of index elements to draw. We want two triangles to form
70+
our quad, and there's three indexes per triangle, so we put 6.
71+
* `type`: This is the type of the index data. The `u32` type is specified with
72+
`GL_UNSIGNED_INT`. I used `u32` out of habit, we could have made our indexes
73+
be `u16` or `u8` as well.
74+
* `indices`: is a pointer to the position within the index buffer to start the
75+
drawing with. Similar to the attribute specification, you pretend the index
76+
buffer starts at address 0 and then you decide the offset you want, and then
77+
cast that to a `*const` pointer.
78+
79+
So the usage looks like this:
80+
81+
```rust
82+
// and then draw!
83+
unsafe {
84+
glClear(GL_COLOR_BUFFER_BIT);
85+
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 as *const _);
86+
}
87+
win.swap_window();
88+
```
89+
90+
## Bonus: Wireframe Mode
91+
92+
Since this lesson is really short let's look at one extra ability we can use.
93+
94+
You often see 3d models with just the outlines of each triangle. "Wireframe
95+
mode" it's sometimes called. We can easily do that with
96+
[`glPolygonMode`](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonMode.xhtml).
97+
98+
* We can specify the `face`, but in the Core profile the only valid value is
99+
`GL_FRONT_AND_BACK` (in Compatibility profile you can also use `GL_FRONT` or
100+
`GL_BACK`).
101+
* We also specify the `mode`. The default is `GL_FILL`, but With `GL_LINE` we
102+
get the wireframe effect. `GL_POINT` is also allowed, but makes it pretty hard
103+
to see what's going on.
104+
105+
All this can go in our `lib.rs` file:
106+
107+
```rust
108+
/// The polygon display modes you can set.
109+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
110+
pub enum PolygonMode {
111+
/// Just show the points.
112+
Point = GL_POINT as isize,
113+
/// Just show the lines.
114+
Line = GL_LINE as isize,
115+
/// Fill in the polygons.
116+
Fill = GL_FILL as isize,
117+
}
118+
119+
/// Sets the font and back polygon mode to the mode given.
120+
pub fn polygon_mode(mode: PolygonMode) {
121+
unsafe { glPolygonMode(GL_FRONT_AND_BACK, mode as GLenum) };
122+
}
123+
```
124+
125+
And then before our main loop we can turn it on:
126+
127+
```rust
128+
learn::polygon_mode(PolygonMode::Line);
129+
```
130+
131+
Now we get a wireframe quad! and it looks like two triangles just like it should!
132+
133+
## Done!
134+
135+
* Code [003-rectangle-elements](https://github.com/rust-tutorials/learn-opengl/blob/master/examples/003-rectangle-elements.rs)

examples/003-rectangle-elements.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use core::{
1212
ptr::null,
1313
};
1414
use learn::{
15-
Buffer, BufferType, Shader, ShaderProgram, ShaderType, VertexArray,
15+
Buffer, BufferType, Shader, ShaderProgram, ShaderType, VertexArray, PolygonMode,
1616
};
1717
use learn_opengl as learn;
1818
use ogl33::*;
@@ -105,6 +105,8 @@ fn main() {
105105
glEnableVertexAttribArray(0);
106106
}
107107

108+
learn::polygon_mode(PolygonMode::Line);
109+
108110
'main_loop: loop {
109111
// handle events this frame
110112
while let Some(event) = sdl.poll_events().and_then(Result::ok) {
@@ -120,7 +122,7 @@ fn main() {
120122
// and then draw!
121123
unsafe {
122124
glClear(GL_COLOR_BUFFER_BIT);
123-
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, null());
125+
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 as *const _);
124126
}
125127
win.swap_window();
126128
}

src/math.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(missing_docs)]
12

23
//! Module for Math that's needed during the Learn OpenGL Rust tutorials.
34
//!

0 commit comments

Comments
 (0)