Extract render module

Description

There are a lot of details that go into setting up an OpenGL context, including several unsafe calls. This change extracts everything related to drawing to a new module to keep the main function simpler.

Right now it doesn't handle any errors, we can improve on that later if needed.

Commands

git clone git@github.com:atsheehan/iridium
cd iridium
git checkout 79583357969ce5ffc185eab9154fc903b3b21165
cargo run --release

Code Changes

Modified src/main.rsGitHub

@@ -1,76 +1,29 @@
1- use std::ffi::CString;
1+ mod render;
22
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;
3+ use render::Renderer;
124 use winit::{
135 event::{Event, WindowEvent},
146 event_loop::EventLoop,
15- window::WindowBuilder,
167 };
178
189 fn main() {
1910 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()));
11+ let mut renderer = Renderer::new(&event_loop);
5212
53- unsafe {
54- gl::ClearColor(0.6, 0.4, 0.8, 1.0);
55- }
56-
5713 event_loop
5814 .run(move |event, window_target| match event {
5915 Event::WindowEvent {
6016 event: WindowEvent::CloseRequested,
6117 window_id,
62- } if window_id == window.id() => {
18+ } if window_id == renderer.window_id() => {
6319 window_target.exit();
6420 }
6521 Event::WindowEvent {
6622 event: WindowEvent::RedrawRequested,
6723 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();
24+ } if window_id == renderer.window_id() => {
25+ renderer.clear();
26+ renderer.present();
7427 }
7528 _ => (),
7629 })
@@ -1,76 +1,29 @@
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,
15- window::WindowBuilder,
16 };
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 {
60 event: WindowEvent::CloseRequested,
61 window_id,
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 })
@@ -1,76 +1,29 @@
1+ mod render;
2
3+ use render::Renderer;
 
 
 
 
 
 
 
 
4 use winit::{
5 event::{Event, WindowEvent},
6 event_loop::EventLoop,
 
7 };
8
9 fn main() {
10 let event_loop = EventLoop::new().unwrap();
11+ let mut renderer = Renderer::new(&event_loop);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
 
 
 
13 event_loop
14 .run(move |event, window_target| match event {
15 Event::WindowEvent {
16 event: WindowEvent::CloseRequested,
17 window_id,
18+ } if window_id == renderer.window_id() => {
19 window_target.exit();
20 }
21 Event::WindowEvent {
22 event: WindowEvent::RedrawRequested,
23 window_id,
24+ } if window_id == renderer.window_id() => {
25+ renderer.clear();
26+ renderer.present();
 
 
 
27 }
28 _ => (),
29 })

Added src/render.rsGitHub

1+ use std::ffi::CString;
2+
3+ use glutin::{
4+ config::ConfigTemplateBuilder,
5+ context::{ContextApi, ContextAttributesBuilder, PossiblyCurrentContext, Version},
6+ display::GetGlDisplay,
7+ prelude::{GlDisplay, NotCurrentGlContext},
8+ surface::{GlSurface, Surface, SurfaceAttributesBuilder, WindowSurface},
9+ };
10+ use glutin_winit::{DisplayBuilder, GlWindow};
11+ use raw_window_handle::HasRawWindowHandle;
12+ use winit::{
13+ event_loop::EventLoop,
14+ window::{Window, WindowBuilder, WindowId},
15+ };
16+
17+ pub(crate) struct Renderer {
18+ window: Window,
19+ context: PossiblyCurrentContext,
20+ surface: Surface<WindowSurface>,
21+ }
22+
23+ impl Renderer {
24+ pub(crate) fn new(event_loop: &EventLoop<()>) -> Self {
25+ let window_builder = WindowBuilder::new().with_title("iridium");
26+
27+ let config_template = ConfigTemplateBuilder::default();
28+ let (window, config) = DisplayBuilder::new()
29+ .with_window_builder(Some(window_builder))
30+ .build(event_loop, config_template, |mut configs| {
31+ configs.next().unwrap()
32+ })
33+ .unwrap();
34+ let window = window.unwrap();
35+ let display = config.display();
36+
37+ let context_attributes = ContextAttributesBuilder::new()
38+ .with_context_api(ContextApi::OpenGl(Some(Version::new(3, 0))))
39+ .build(Some(window.raw_window_handle()));
40+
41+ let surface_attributes =
42+ window.build_surface_attributes(SurfaceAttributesBuilder::default());
43+ let surface = unsafe {
44+ display
45+ .create_window_surface(&config, &surface_attributes)
46+ .unwrap()
47+ };
48+
49+ let context = unsafe {
50+ display
51+ .create_context(&config, &context_attributes)
52+ .unwrap()
53+ .make_current(&surface)
54+ .unwrap()
55+ };
56+
57+ gl::load_with(|s| display.get_proc_address(&CString::new(s).unwrap()));
58+
59+ unsafe {
60+ gl::ClearColor(0.6, 0.4, 0.8, 1.0);
61+ }
62+
63+ Self {
64+ window,
65+ surface,
66+ context,
67+ }
68+ }
69+
70+ pub(crate) fn window_id(&self) -> WindowId {
71+ self.window.id()
72+ }
73+
74+ pub(crate) fn clear(&mut self) {
75+ unsafe {
76+ gl::Clear(gl::COLOR_BUFFER_BIT);
77+ }
78+ }
79+
80+ pub(crate) fn present(&mut self) {
81+ self.surface.swap_buffers(&self.context).unwrap();
82+ }
83+ }
1+ use std::ffi::CString;
2+
3+ use glutin::{
4+ config::ConfigTemplateBuilder,
5+ context::{ContextApi, ContextAttributesBuilder, PossiblyCurrentContext, Version},
6+ display::GetGlDisplay,
7+ prelude::{GlDisplay, NotCurrentGlContext},
8+ surface::{GlSurface, Surface, SurfaceAttributesBuilder, WindowSurface},
9+ };
10+ use glutin_winit::{DisplayBuilder, GlWindow};
11+ use raw_window_handle::HasRawWindowHandle;
12+ use winit::{
13+ event_loop::EventLoop,
14+ window::{Window, WindowBuilder, WindowId},
15+ };
16+
17+ pub(crate) struct Renderer {
18+ window: Window,
19+ context: PossiblyCurrentContext,
20+ surface: Surface<WindowSurface>,
21+ }
22+
23+ impl Renderer {
24+ pub(crate) fn new(event_loop: &EventLoop<()>) -> Self {
25+ let window_builder = WindowBuilder::new().with_title("iridium");
26+
27+ let config_template = ConfigTemplateBuilder::default();
28+ let (window, config) = DisplayBuilder::new()
29+ .with_window_builder(Some(window_builder))
30+ .build(event_loop, config_template, |mut configs| {
31+ configs.next().unwrap()
32+ })
33+ .unwrap();
34+ let window = window.unwrap();
35+ let display = config.display();
36+
37+ let context_attributes = ContextAttributesBuilder::new()
38+ .with_context_api(ContextApi::OpenGl(Some(Version::new(3, 0))))
39+ .build(Some(window.raw_window_handle()));
40+
41+ let surface_attributes =
42+ window.build_surface_attributes(SurfaceAttributesBuilder::default());
43+ let surface = unsafe {
44+ display
45+ .create_window_surface(&config, &surface_attributes)
46+ .unwrap()
47+ };
48+
49+ let context = unsafe {
50+ display
51+ .create_context(&config, &context_attributes)
52+ .unwrap()
53+ .make_current(&surface)
54+ .unwrap()
55+ };
56+
57+ gl::load_with(|s| display.get_proc_address(&CString::new(s).unwrap()));
58+
59+ unsafe {
60+ gl::ClearColor(0.6, 0.4, 0.8, 1.0);
61+ }
62+
63+ Self {
64+ window,
65+ surface,
66+ context,
67+ }
68+ }
69+
70+ pub(crate) fn window_id(&self) -> WindowId {
71+ self.window.id()
72+ }
73+
74+ pub(crate) fn clear(&mut self) {
75+ unsafe {
76+ gl::Clear(gl::COLOR_BUFFER_BIT);
77+ }
78+ }
79+
80+ pub(crate) fn present(&mut self) {
81+ self.surface.swap_buffers(&self.context).unwrap();
82+ }
83+ }