1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use crate::{GlFramebuffer, GlProgram, GolemError};
use glow::HasContext;
use std::cell::RefCell;
use std::rc::Rc;
/// The context required to interact with the GPU
pub struct Context(pub(crate) Rc<ContextContents>);
pub(crate) struct ContextContents {
pub(crate) gl: glow::Context,
pub(crate) current_program: RefCell<Option<GlProgram>>,
pub(crate) current_surface: RefCell<Option<GlFramebuffer>>,
#[cfg(not(target_arch = "wasm32"))]
vao: u32,
}
impl Drop for ContextContents {
fn drop(&mut self) {
// https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glDeleteVertexArrays.xhtml
// glow handles passing in the pointer to our value, and GL will silently ignore invalid
// values
#[cfg(not(target_arch = "wasm32"))]
unsafe {
self.gl.delete_vertex_array(self.vao);
}
}
}
impl Context {
/// Create an instance from an OpenGL context
pub fn from_glow(gl: glow::Context) -> Result<Context, GolemError> {
#[cfg(not(target_arch = "wasm32"))]
let vao = unsafe {
// https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGenVertexArrays.xhtml
// glow handles passing in '1' and returning the value to us
let vao = gl.create_vertex_array()?;
// https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBindVertexArray.xhtml
// In this case, we know 'vao' must be a valid vao because we just constructed it
gl.bind_vertex_array(Some(vao));
vao
};
let contents = Context(Rc::new(ContextContents {
gl,
current_program: RefCell::new(None),
current_surface: RefCell::new(None),
#[cfg(not(target_arch = "wasm32"))]
vao,
}));
contents.set_clear_color(0.0, 0.0, 0.0, 1.0);
Ok(contents)
}
/// Set the section of the framebuffer that will be rendered to
///
/// By default, this is the entire internal area of the window. When switching to a
/// [`Surface`], it's generally important to set the viewport to its area.
///
/// [`Surface`]: crate::Surface
pub fn set_viewport(&self, x: u32, y: u32, width: u32, height: u32) {
unsafe {
self.0
.gl
.viewport(x as i32, y as i32, width as i32, height as i32);
}
}
/// Set the color the render target will be cleared to by [`clear`]
///
/// [`clear`]: Context::clear
pub fn set_clear_color(&self, r: f32, g: f32, b: f32, a: f32) {
// https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glClearColor.xhtml
// Set the clear color to (r, g, b, a)
unsafe {
self.0.gl.clear_color(r, g, b, a);
}
}
/// Clear the current render target to the render color (see [`set_clear_color`])
///
/// [`set_clear_color`]: Context::set_clear_color
pub fn clear(&self) {
let gl = &self.0.gl;
unsafe {
gl.clear(glow::COLOR_BUFFER_BIT | glow::DEPTH_BUFFER_BIT);
}
}
}