Create OpenGL context
Description
TODO update for glutin 0.31.0
To use OpenGL, we need an OpenGL context. The context is what stores the current OpenGL state which we manipulate via glFunctions (e.g. storing the background color set via glClearColor).
There are several platform-specific APIs for creating an OpenGL context: WGL for Windows, CGL for Macs, GLX for X Windows. There's also EGL which is used by Wayland and mobile clients to create OpenGL ES context.
Fortunately, the glutin library handles cross-platform context creation and integrates with winit. There are several steps to the process.
The four main concepts we'll encounter are:
- the display, which roughly corresponds to some connection to a display server,
- the surface, which is something we can draw onto. In our case we are using a window surface, but there can also be other surfaces for rendering offscreen.
- the config, which describes the surface,
- and the context, which stores the current state of OpenGL.
We also need to load OpenGL functions which we use the gl crate for.
We then make our first OpenGL call with gl::ClearColor. This stores the color in the active context, so that when we call gl::Clear later it will set the screen to a nice amethyst purple.
Screenshot
Commands
git clone git@github.com:atsheehan/iridium
cd iridium
git checkout 72293c34eb24ec30c0519d18f02510573e441685
cargo run --release
Code Changes
Modified Cargo.lockGitHub
Hiding contents due to file size.
Modified Cargo.tomlGitHub
@@ -9,3 +9,9 @@99
1010 # Cross-platform window creation and event handling
1111 winit = "0.29.2"
12+
13+ # OpenGL context creation
14+ glutin = "0.31.0"
15+ glutin-winit = "0.4.2"
16+ raw-window-handle = "0.5.2"
17+ gl = "0.14.0"
@@ -9,3 +9,9 @@9
10 # Cross-platform window creation and event handling
11 winit = "0.29.2"
@@ -9,3 +9,9 @@9
10 # Cross-platform window creation and event handling
11 winit = "0.29.2"
12+
13+ # OpenGL context creation
14+ glutin = "0.31.0"
15+ glutin-winit = "0.4.2"
16+ raw-window-handle = "0.5.2"
17+ gl = "0.14.0"
Modified src/main.rsGitHub
@@ -1,3 +1,14 @@1+ use std::ffi::CString;
2+
3+ use glutin::{
4+ config::ConfigTemplateBuilder,
5+ context::{ContextApi, ContextAttributesBuilder, Version},
6+ display::GetGlDisplay,
7+ prelude::{GlDisplay, NotCurrentGlContext},
8+ surface::{GlSurface, SurfaceAttributesBuilder},
9+ };
10+ use glutin_winit::{DisplayBuilder, GlWindow};
11+ use raw_window_handle::HasRawWindowHandle;
112 use winit::{
213 event::{Event, WindowEvent},
314 event_loop::EventLoop,
@@ -6,11 +17,43 @@617
718 fn main() {
819 let event_loop = EventLoop::new().unwrap();
9- let window = WindowBuilder::new()
10- .with_title("iridium")
11- .build(&event_loop)
20+ let window_builder = WindowBuilder::new().with_title("iridium");
21+
22+ let config_template = ConfigTemplateBuilder::default();
23+ let (window, config) = DisplayBuilder::new()
24+ .with_window_builder(Some(window_builder))
25+ .build(&event_loop, config_template, |mut configs| {
26+ configs.next().unwrap()
27+ })
1228 .unwrap();
29+ let window = window.unwrap();
30+ let display = config.display();
1331
32+ let context_attributes = ContextAttributesBuilder::new()
33+ .with_context_api(ContextApi::OpenGl(Some(Version::new(3, 0))))
34+ .build(Some(window.raw_window_handle()));
35+
36+ let surface_attributes = window.build_surface_attributes(SurfaceAttributesBuilder::default());
37+ let surface = unsafe {
38+ display
39+ .create_window_surface(&config, &surface_attributes)
40+ .unwrap()
41+ };
42+
43+ let context = unsafe {
44+ display
45+ .create_context(&config, &context_attributes)
46+ .unwrap()
47+ .make_current(&surface)
48+ .unwrap()
49+ };
50+
51+ gl::load_with(|s| display.get_proc_address(&CString::new(s).unwrap()));
52+
53+ unsafe {
54+ gl::ClearColor(0.6, 0.4, 0.8, 1.0);
55+ }
56+
1457 event_loop
1558 .run(move |event, window_target| match event {
1659 Event::WindowEvent {
@@ -19,6 +62,16 @@1962 } if window_id == window.id() => {
2063 window_target.exit();
2164 }
65+ Event::WindowEvent {
66+ event: WindowEvent::RedrawRequested,
67+ window_id,
68+ } if window_id == window.id() => {
69+ unsafe {
70+ gl::Clear(gl::COLOR_BUFFER_BIT);
71+ }
72+
73+ surface.swap_buffers(&context).unwrap();
74+ }
2275 _ => (),
2376 })
2477 .unwrap();
@@ -1,3 +1,14 @@ 1 use winit::{
2 event::{Event, WindowEvent},
3 event_loop::EventLoop,
@@ -6,11 +17,43 @@6
7 fn main() {
8 let event_loop = EventLoop::new().unwrap();
9- let window = WindowBuilder::new()
10- .with_title("iridium")
11- .build(&event_loop)
12 .unwrap();
13
14 event_loop
15 .run(move |event, window_target| match event {
16 Event::WindowEvent {
@@ -19,6 +62,16 @@19 } if window_id == window.id() => {
20 window_target.exit();
21 }
22 _ => (),
23 })
24 .unwrap();
@@ -1,3 +1,14 @@1+ use std::ffi::CString;
2+
3+ use glutin::{
4+ config::ConfigTemplateBuilder,
5+ context::{ContextApi, ContextAttributesBuilder, Version},
6+ display::GetGlDisplay,
7+ prelude::{GlDisplay, NotCurrentGlContext},
8+ surface::{GlSurface, SurfaceAttributesBuilder},
9+ };
10+ use glutin_winit::{DisplayBuilder, GlWindow};
11+ use raw_window_handle::HasRawWindowHandle;
12 use winit::{
13 event::{Event, WindowEvent},
14 event_loop::EventLoop,
@@ -6,11 +17,43 @@17
18 fn main() {
19 let event_loop = EventLoop::new().unwrap();
20+ let window_builder = WindowBuilder::new().with_title("iridium");
21+
22+ let config_template = ConfigTemplateBuilder::default();
23+ let (window, config) = DisplayBuilder::new()
24+ .with_window_builder(Some(window_builder))
25+ .build(&event_loop, config_template, |mut configs| {
26+ configs.next().unwrap()
27+ })
28 .unwrap();
29+ let window = window.unwrap();
30+ let display = config.display();
31
32+ let context_attributes = ContextAttributesBuilder::new()
33+ .with_context_api(ContextApi::OpenGl(Some(Version::new(3, 0))))
34+ .build(Some(window.raw_window_handle()));
35+
36+ let surface_attributes = window.build_surface_attributes(SurfaceAttributesBuilder::default());
37+ let surface = unsafe {
38+ display
39+ .create_window_surface(&config, &surface_attributes)
40+ .unwrap()
41+ };
42+
43+ let context = unsafe {
44+ display
45+ .create_context(&config, &context_attributes)
46+ .unwrap()
47+ .make_current(&surface)
48+ .unwrap()
49+ };
50+
51+ gl::load_with(|s| display.get_proc_address(&CString::new(s).unwrap()));
52+
53+ unsafe {
54+ gl::ClearColor(0.6, 0.4, 0.8, 1.0);
55+ }
56+
57 event_loop
58 .run(move |event, window_target| match event {
59 Event::WindowEvent {
@@ -19,6 +62,16 @@62 } if window_id == window.id() => {
63 window_target.exit();
64 }
65+ Event::WindowEvent {
66+ event: WindowEvent::RedrawRequested,
67+ window_id,
68+ } if window_id == window.id() => {
69+ unsafe {
70+ gl::Clear(gl::COLOR_BUFFER_BIT);
71+ }
72+
73+ surface.swap_buffers(&context).unwrap();
74+ }
75 _ => (),
76 })
77 .unwrap();