|
| 1 | +# Drawing A Triangle |
| 2 | + |
| 3 | +In this lesson, we'll do a lot of setup just to be able to draw a single |
| 4 | +triangle. |
| 5 | + |
| 6 | +Don't worry, once you do the first batch of setup, drawing that _second_ |
| 7 | +triangle is easy. |
| 8 | + |
| 9 | +## Load The Opengl Functions |
| 10 | + |
| 11 | +Unlike most libraries that you can use in a program, OpenGL cannot be statically |
| 12 | +linked to. Well, you can static link to very old versions, but any sort of newer |
| 13 | +OpenGL library is installed on the user's system as a dynamic library that you |
| 14 | +load at runtime. This way the user can get their video driver updates and then your program just loads in the new driver file the next time it turns on. |
| 15 | + |
| 16 | +The details aren't too important to the rest of what we want to do, so I won't |
| 17 | +discuss it here. Perhaps an appendix page or something at some point in the |
| 18 | +future. The `ogl33` crate handles it for us. As a reminder, you could also use |
| 19 | +the `gl` or `glow` crates. |
| 20 | + |
| 21 | +After we open the window, we just say that we want to load up every OpenGL |
| 22 | +function. |
| 23 | + |
| 24 | +```rust |
| 25 | +unsafe { |
| 26 | + load_gl_with(|f_name| win.get_proc_address(f_name)); |
| 27 | +} |
| 28 | +``` |
| 29 | + |
| 30 | +## Set The "Clear" Screen Color |
| 31 | + |
| 32 | +When we clear the previous image's data at the start of our drawing, by default it would clear to black. Since we'll only have one thing at a time to draw for a little bit, let's use a slightly softer sort of color. |
| 33 | + |
| 34 | +We just need to call |
| 35 | +[`glClearColor`](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glClearColor.xhtml) |
| 36 | +with the red, green, blue, and alpha intensities that we want to use. |
| 37 | + |
| 38 | +```rust |
| 39 | +unsafe { |
| 40 | + glClearColor(0.2, 0.3, 0.3, 1.0); |
| 41 | +} |
| 42 | +``` |
| 43 | + |
| 44 | +This is a blue-green sort of color that's only a little bit away from being |
| 45 | +gray. You can _kinda_ tell that even before we open the window. The channel |
| 46 | +values are all close (which is gray), but there's a little less red, so it tilts |
| 47 | +towards being a blue-green. |
| 48 | + |
| 49 | +The alpha value isn't important for now because our window itself isn't |
| 50 | +transparent (so you can't see pixels behind it) and we're not doing any color |
| 51 | +blending yet (so the alpha of the clear color compared to some other color |
| 52 | +doesn't come into play). Eventually it might matter, so we'll just leave it on |
| 53 | +"fully opaque" for now. |
| 54 | + |
| 55 | +## Send A Triangle |
| 56 | + |
| 57 | +At this point there's two main actions we need to take before we're ready for our triangle to be drawn. |
| 58 | + |
| 59 | +* We need to get some triangle data to the video card in a way it understands. |
| 60 | +* We need to get a program to the video card so that it can make use of the data. |
| 61 | + |
| 62 | +Neither task depends on the other, so we'll send our triangle data first and |
| 63 | +then send our program. |
| 64 | + |
| 65 | +### Generate A Vertex Array Object |
| 66 | + |
| 67 | +A [Vertex Array |
| 68 | +Object](https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_Array_Object) |
| 69 | +(VAO) is an object that collects together a few different bits of stuff. |
| 70 | +Basically, at any given moment there either is a Vertex Array Object "bound", |
| 71 | +meaning it's the active one, or there is not one bound, which makes basically |
| 72 | +all commands that relate to buffering data and describing data invalid. Since we |
| 73 | +want to buffer some data and describe it, we need to have a VAO bound. |
| 74 | + |
| 75 | +You make a vertex array object with |
| 76 | +[`glGenVertexArrays`](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGenVertexArrays.xhtml). |
| 77 | +It takes the length of an array to fill, and a pointer to the start of that |
| 78 | +array. Then it fills the array with the names of a bunch of new VAOs. You're |
| 79 | +allowed to make a lot of vertex arrays at once if you want, but we just need one |
| 80 | +for now. Luckily, a pointer to just one thing is the same as a pointer to an |
| 81 | +array of length 1. |
| 82 | + |
| 83 | +Also, `glGenVertexArrays` _shouldn't_ ever return 0, but if some sort of bug |
| 84 | +happened it could, so we'll throw in a little assert just to check that. |
| 85 | + |
| 86 | +```rust |
| 87 | +unsafe { |
| 88 | + let mut vao = 0; |
| 89 | + glGenVertexArrays(1, &mut vao); |
| 90 | + assert_ne!(vao, 0); |
| 91 | +} |
| 92 | +``` |
| 93 | + |
| 94 | +Once we have a VAO we can "bind" it with |
| 95 | +[`glBindVertexArray`](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBindVertexArray.xhtml) |
| 96 | +to make it the active VAO. This is a _context wide_ effect, so now all GL |
| 97 | +functions in our GL context will do whatever they do with this VAO as the VAO to |
| 98 | +work with. |
| 99 | + |
| 100 | +### Generate A Vertex Buffer Object |
| 101 | + |
| 102 | +To actually get some bytes of data to the video card we need a [Vertex Buffer |
| 103 | +Object](https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_Buffer_Object) |
| 104 | +(VBO) to go with our Vertex Array Object. You might get sick of the words |
| 105 | +"vertex" and "object" by the time you've read this whole book. |
| 106 | + |
| 107 | +This time things are a little different than with the VAO. Instead of calling a |
| 108 | +function to make and bind specifically a _vertex_ buffer object, there's just a |
| 109 | +common function to make and bind buffers of all sorts. It's called |
| 110 | +[`glGenBuffers`](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGenBuffers.xhtml), |
| 111 | +and it works mostly the same as `glGenVertexArrays` did, you pass a length and a |
| 112 | +pointer and it fills an array. |
| 113 | + |
| 114 | +```rust |
| 115 | +unsafe { |
| 116 | + let mut vbo = 0; |
| 117 | + glGenBuffers(1, &mut vbo); |
| 118 | + assert_ne!(vbo, 0); |
| 119 | +} |
| 120 | +``` |
| 121 | + |
| 122 | +Now that we have a buffer, we can bind it to the binding target that we want. [`glBindBuffer`](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBindBuffer.xhtml) takes a target name and a buffer. As you can see on that page, there's a whole lot of options, but for now we just want `GL_ARRAY_BUFFER`. |
| 123 | + |
| 124 | +```rust |
| 125 | +unsafe { |
| 126 | + glBindBuffer(GL_ARRAY_BUFFER, vbo); |
| 127 | +} |
| 128 | +``` |
| 129 | + |
| 130 | +## Vsync |
| 131 | + |
| 132 | +Finally, let's turn on |
| 133 | +[vsync](https://en.wikipedia.org/wiki/Screen_tearing#Vertical_synchronization), |
| 134 | +which will make our `swap_window` call block the program until the image has |
| 135 | +actually been presented to the user. This makes the whole program run no faster |
| 136 | +than the screen's refresh rate, usually at least 60fps (sometimes more these |
| 137 | +days). This is usually a good thing. We can't show them images faster than the |
| 138 | +screen will present them anyway, so we can let the CPU cool down a bit, maybe |
| 139 | +save the battery even if they're on a laptop. |
| 140 | + |
| 141 | +```rust |
| 142 | +// this goes any time after window creation. |
| 143 | +win.set_swap_interval(SwapInterval::Vsync); |
| 144 | +``` |
| 145 | + |
| 146 | +## Done! |
| 147 | + |
| 148 | +* Example Code: [001-triangle-arrays1](https://github.com/rust-tutorials/learn-opengl/blob/master/examples/001-triangle-arrays1.rs) |
| 149 | + |
| 150 | +## Cleanup |
| 151 | + |
| 152 | +* Example Code: [002-triangle-arrays2](https://github.com/rust-tutorials/learn-opengl/blob/master/examples/002-triangle-arrays2.rs) |
0 commit comments