glow painter improvements (#1406)
* Add viewport info to PaintCallback * glow: be more explicit with more state * glow: Refactor VAO
This commit is contained in:
parent
6f10e2e725
commit
ea9393aa9b
|
|
@ -75,7 +75,7 @@ impl MyApp {
|
||||||
|
|
||||||
let callback = egui::PaintCallback {
|
let callback = egui::PaintCallback {
|
||||||
rect,
|
rect,
|
||||||
callback: std::sync::Arc::new(move |render_ctx| {
|
callback: std::sync::Arc::new(move |_info, render_ctx| {
|
||||||
if let Some(painter) = render_ctx.downcast_ref::<egui_glow::Painter>() {
|
if let Some(painter) = render_ctx.downcast_ref::<egui_glow::Painter>() {
|
||||||
rotating_triangle.lock().paint(painter.gl(), angle);
|
rotating_triangle.lock().paint(painter.gl(), angle);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -307,8 +307,8 @@ pub use epaint::{
|
||||||
color, mutex,
|
color, mutex,
|
||||||
text::{FontData, FontDefinitions, FontFamily, FontId, FontTweak},
|
text::{FontData, FontDefinitions, FontFamily, FontId, FontTweak},
|
||||||
textures::TexturesDelta,
|
textures::TexturesDelta,
|
||||||
AlphaImage, ClippedPrimitive, Color32, ColorImage, ImageData, Mesh, PaintCallback, Rgba,
|
AlphaImage, ClippedPrimitive, Color32, ColorImage, ImageData, Mesh, PaintCallback,
|
||||||
Rounding, Shape, Stroke, TextureHandle, TextureId,
|
PaintCallbackInfo, Rgba, Rounding, Shape, Stroke, TextureHandle, TextureId,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod text {
|
pub mod text {
|
||||||
|
|
|
||||||
|
|
@ -37,12 +37,12 @@ pub struct Painter {
|
||||||
u_sampler: glow::UniformLocation,
|
u_sampler: glow::UniformLocation,
|
||||||
is_webgl_1: bool,
|
is_webgl_1: bool,
|
||||||
is_embedded: bool,
|
is_embedded: bool,
|
||||||
vertex_array: crate::vao::VAO,
|
vao: crate::vao::VertexArrayObject,
|
||||||
srgb_support: bool,
|
srgb_support: bool,
|
||||||
/// The filter used for subsequent textures.
|
/// The filter used for subsequent textures.
|
||||||
texture_filter: TextureFilter,
|
texture_filter: TextureFilter,
|
||||||
post_process: Option<PostProcess>,
|
post_process: Option<PostProcess>,
|
||||||
vertex_buffer: glow::Buffer,
|
vbo: glow::Buffer,
|
||||||
element_array_buffer: glow::Buffer,
|
element_array_buffer: glow::Buffer,
|
||||||
|
|
||||||
textures: HashMap<egui::TextureId, glow::Texture>,
|
textures: HashMap<egui::TextureId, glow::Texture>,
|
||||||
|
|
@ -100,11 +100,6 @@ impl Painter {
|
||||||
|
|
||||||
let max_texture_side = unsafe { gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) } as usize;
|
let max_texture_side = unsafe { gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) } as usize;
|
||||||
|
|
||||||
let support_vao = crate::vao::supports_vao(&gl);
|
|
||||||
if !support_vao {
|
|
||||||
tracing::debug!("VAO not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
let shader_version = ShaderVersion::get(&gl);
|
let shader_version = ShaderVersion::get(&gl);
|
||||||
let is_webgl_1 = shader_version == ShaderVersion::Es100;
|
let is_webgl_1 = shader_version == ShaderVersion::Es100;
|
||||||
let header = shader_version.version();
|
let header = shader_version.version();
|
||||||
|
|
@ -122,7 +117,6 @@ impl Painter {
|
||||||
Some(PostProcess::new(
|
Some(PostProcess::new(
|
||||||
gl.clone(),
|
gl.clone(),
|
||||||
shader_prefix,
|
shader_prefix,
|
||||||
support_vao,
|
|
||||||
is_webgl_1,
|
is_webgl_1,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
|
@ -173,47 +167,44 @@ impl Painter {
|
||||||
gl.delete_shader(frag);
|
gl.delete_shader(frag);
|
||||||
let u_screen_size = gl.get_uniform_location(program, "u_screen_size").unwrap();
|
let u_screen_size = gl.get_uniform_location(program, "u_screen_size").unwrap();
|
||||||
let u_sampler = gl.get_uniform_location(program, "u_sampler").unwrap();
|
let u_sampler = gl.get_uniform_location(program, "u_sampler").unwrap();
|
||||||
let vertex_buffer = gl.create_buffer()?;
|
|
||||||
let element_array_buffer = gl.create_buffer()?;
|
let vbo = gl.create_buffer()?;
|
||||||
gl.bind_buffer(glow::ARRAY_BUFFER, Some(vertex_buffer));
|
|
||||||
let a_pos_loc = gl.get_attrib_location(program, "a_pos").unwrap();
|
let a_pos_loc = gl.get_attrib_location(program, "a_pos").unwrap();
|
||||||
let a_tc_loc = gl.get_attrib_location(program, "a_tc").unwrap();
|
let a_tc_loc = gl.get_attrib_location(program, "a_tc").unwrap();
|
||||||
let a_srgba_loc = gl.get_attrib_location(program, "a_srgba").unwrap();
|
let a_srgba_loc = gl.get_attrib_location(program, "a_srgba").unwrap();
|
||||||
let mut vertex_array = if support_vao {
|
|
||||||
crate::vao::VAO::native(&gl)
|
|
||||||
} else {
|
|
||||||
crate::vao::VAO::emulated()
|
|
||||||
};
|
|
||||||
vertex_array.bind_vertex_array(&gl);
|
|
||||||
vertex_array.bind_buffer(&gl, &vertex_buffer);
|
|
||||||
let stride = std::mem::size_of::<Vertex>() as i32;
|
let stride = std::mem::size_of::<Vertex>() as i32;
|
||||||
let position_buffer_info = vao::BufferInfo {
|
let buffer_infos = vec![
|
||||||
location: a_pos_loc,
|
vao::BufferInfo {
|
||||||
vector_size: 2,
|
location: a_pos_loc,
|
||||||
data_type: glow::FLOAT,
|
vector_size: 2,
|
||||||
normalized: false,
|
data_type: glow::FLOAT,
|
||||||
stride,
|
normalized: false,
|
||||||
offset: offset_of!(Vertex, pos) as i32,
|
stride,
|
||||||
};
|
offset: offset_of!(Vertex, pos) as i32,
|
||||||
let tex_coord_buffer_info = vao::BufferInfo {
|
},
|
||||||
location: a_tc_loc,
|
vao::BufferInfo {
|
||||||
vector_size: 2,
|
location: a_tc_loc,
|
||||||
data_type: glow::FLOAT,
|
vector_size: 2,
|
||||||
normalized: false,
|
data_type: glow::FLOAT,
|
||||||
stride,
|
normalized: false,
|
||||||
offset: offset_of!(Vertex, uv) as i32,
|
stride,
|
||||||
};
|
offset: offset_of!(Vertex, uv) as i32,
|
||||||
let color_buffer_info = vao::BufferInfo {
|
},
|
||||||
location: a_srgba_loc,
|
vao::BufferInfo {
|
||||||
vector_size: 4,
|
location: a_srgba_loc,
|
||||||
data_type: glow::UNSIGNED_BYTE,
|
vector_size: 4,
|
||||||
normalized: false,
|
data_type: glow::UNSIGNED_BYTE,
|
||||||
stride,
|
normalized: false,
|
||||||
offset: offset_of!(Vertex, color) as i32,
|
stride,
|
||||||
};
|
offset: offset_of!(Vertex, color) as i32,
|
||||||
vertex_array.add_new_attribute(&gl, position_buffer_info);
|
},
|
||||||
vertex_array.add_new_attribute(&gl, tex_coord_buffer_info);
|
];
|
||||||
vertex_array.add_new_attribute(&gl, color_buffer_info);
|
let vao = crate::vao::VertexArrayObject::new(&gl, vbo, buffer_infos);
|
||||||
|
|
||||||
|
let element_array_buffer = gl.create_buffer()?;
|
||||||
|
|
||||||
check_for_gl_error!(&gl, "after Painter::new");
|
check_for_gl_error!(&gl, "after Painter::new");
|
||||||
|
|
||||||
Ok(Painter {
|
Ok(Painter {
|
||||||
|
|
@ -224,11 +215,11 @@ impl Painter {
|
||||||
u_sampler,
|
u_sampler,
|
||||||
is_webgl_1,
|
is_webgl_1,
|
||||||
is_embedded: matches!(shader_version, ShaderVersion::Es100 | ShaderVersion::Es300),
|
is_embedded: matches!(shader_version, ShaderVersion::Es100 | ShaderVersion::Es300),
|
||||||
vertex_array,
|
vao,
|
||||||
srgb_support,
|
srgb_support,
|
||||||
texture_filter: Default::default(),
|
texture_filter: Default::default(),
|
||||||
post_process,
|
post_process,
|
||||||
vertex_buffer,
|
vbo,
|
||||||
element_array_buffer,
|
element_array_buffer,
|
||||||
textures: Default::default(),
|
textures: Default::default(),
|
||||||
#[cfg(feature = "epi")]
|
#[cfg(feature = "epi")]
|
||||||
|
|
@ -256,9 +247,13 @@ impl Painter {
|
||||||
self.gl.enable(glow::SCISSOR_TEST);
|
self.gl.enable(glow::SCISSOR_TEST);
|
||||||
// egui outputs mesh in both winding orders
|
// egui outputs mesh in both winding orders
|
||||||
self.gl.disable(glow::CULL_FACE);
|
self.gl.disable(glow::CULL_FACE);
|
||||||
|
self.gl.disable(glow::DEPTH_TEST);
|
||||||
|
|
||||||
|
self.gl.color_mask(true, true, true, true);
|
||||||
|
|
||||||
self.gl.enable(glow::BLEND);
|
self.gl.enable(glow::BLEND);
|
||||||
self.gl.blend_equation(glow::FUNC_ADD);
|
self.gl
|
||||||
|
.blend_equation_separate(glow::FUNC_ADD, glow::FUNC_ADD);
|
||||||
self.gl.blend_func_separate(
|
self.gl.blend_func_separate(
|
||||||
// egui outputs colors with premultiplied alpha:
|
// egui outputs colors with premultiplied alpha:
|
||||||
glow::ONE,
|
glow::ONE,
|
||||||
|
|
@ -285,8 +280,8 @@ impl Painter {
|
||||||
.uniform_2_f32(Some(&self.u_screen_size), width_in_points, height_in_points);
|
.uniform_2_f32(Some(&self.u_screen_size), width_in_points, height_in_points);
|
||||||
self.gl.uniform_1_i32(Some(&self.u_sampler), 0);
|
self.gl.uniform_1_i32(Some(&self.u_sampler), 0);
|
||||||
self.gl.active_texture(glow::TEXTURE0);
|
self.gl.active_texture(glow::TEXTURE0);
|
||||||
self.vertex_array.bind_vertex_array(&self.gl);
|
|
||||||
|
|
||||||
|
self.vao.bind(&self.gl);
|
||||||
self.gl
|
self.gl
|
||||||
.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.element_array_buffer));
|
.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.element_array_buffer));
|
||||||
|
|
||||||
|
|
@ -380,7 +375,13 @@ impl Painter {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
callback.call(self);
|
let info = egui::PaintCallbackInfo {
|
||||||
|
rect: callback.rect,
|
||||||
|
pixels_per_point,
|
||||||
|
screen_size_px: inner_size,
|
||||||
|
};
|
||||||
|
|
||||||
|
callback.call(&info, self);
|
||||||
|
|
||||||
check_for_gl_error!(&self.gl, "callback");
|
check_for_gl_error!(&self.gl, "callback");
|
||||||
|
|
||||||
|
|
@ -395,8 +396,9 @@ impl Painter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.vertex_array.unbind_vertex_array(&self.gl);
|
self.vao.unbind(&self.gl);
|
||||||
self.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None);
|
self.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None);
|
||||||
|
|
||||||
if let Some(ref post_process) = self.post_process {
|
if let Some(ref post_process) = self.post_process {
|
||||||
|
|
@ -414,8 +416,7 @@ impl Painter {
|
||||||
debug_assert!(mesh.is_valid());
|
debug_assert!(mesh.is_valid());
|
||||||
if let Some(texture) = self.get_texture(mesh.texture_id) {
|
if let Some(texture) = self.get_texture(mesh.texture_id) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.gl
|
self.gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vbo));
|
||||||
.bind_buffer(glow::ARRAY_BUFFER, Some(self.vertex_buffer));
|
|
||||||
self.gl.buffer_data_u8_slice(
|
self.gl.buffer_data_u8_slice(
|
||||||
glow::ARRAY_BUFFER,
|
glow::ARRAY_BUFFER,
|
||||||
bytemuck::cast_slice(&mesh.vertices),
|
bytemuck::cast_slice(&mesh.vertices),
|
||||||
|
|
@ -600,7 +601,7 @@ impl Painter {
|
||||||
for tex in self.textures.values() {
|
for tex in self.textures.values() {
|
||||||
self.gl.delete_texture(*tex);
|
self.gl.delete_texture(*tex);
|
||||||
}
|
}
|
||||||
self.gl.delete_buffer(self.vertex_buffer);
|
self.gl.delete_buffer(self.vbo);
|
||||||
self.gl.delete_buffer(self.element_array_buffer);
|
self.gl.delete_buffer(self.element_array_buffer);
|
||||||
for t in &self.textures_to_destroy {
|
for t in &self.textures_to_destroy {
|
||||||
self.gl.delete_texture(*t);
|
self.gl.delete_texture(*t);
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ pub(crate) struct PostProcess {
|
||||||
gl: std::rc::Rc<glow::Context>,
|
gl: std::rc::Rc<glow::Context>,
|
||||||
pos_buffer: glow::Buffer,
|
pos_buffer: glow::Buffer,
|
||||||
index_buffer: glow::Buffer,
|
index_buffer: glow::Buffer,
|
||||||
vertex_array: crate::vao::VAO,
|
vao: crate::vao::VertexArrayObject,
|
||||||
is_webgl_1: bool,
|
is_webgl_1: bool,
|
||||||
texture: glow::Texture,
|
texture: glow::Texture,
|
||||||
texture_size: (i32, i32),
|
texture_size: (i32, i32),
|
||||||
|
|
@ -22,7 +22,6 @@ impl PostProcess {
|
||||||
pub(crate) unsafe fn new(
|
pub(crate) unsafe fn new(
|
||||||
gl: std::rc::Rc<glow::Context>,
|
gl: std::rc::Rc<glow::Context>,
|
||||||
shader_prefix: &str,
|
shader_prefix: &str,
|
||||||
need_to_emulate_vao: bool,
|
|
||||||
is_webgl_1: bool,
|
is_webgl_1: bool,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
|
|
@ -125,22 +124,18 @@ impl PostProcess {
|
||||||
let a_pos_loc = gl
|
let a_pos_loc = gl
|
||||||
.get_attrib_location(program, "a_pos")
|
.get_attrib_location(program, "a_pos")
|
||||||
.ok_or_else(|| "failed to get location of a_pos".to_string())?;
|
.ok_or_else(|| "failed to get location of a_pos".to_string())?;
|
||||||
let mut vertex_array = if need_to_emulate_vao {
|
let vao = crate::vao::VertexArrayObject::new(
|
||||||
crate::vao::VAO::emulated()
|
&gl,
|
||||||
} else {
|
pos_buffer,
|
||||||
crate::vao::VAO::native(&gl)
|
vec![BufferInfo {
|
||||||
};
|
location: a_pos_loc,
|
||||||
vertex_array.bind_vertex_array(&gl);
|
vector_size: 2,
|
||||||
vertex_array.bind_buffer(&gl, &pos_buffer);
|
data_type: glow::FLOAT,
|
||||||
let buffer_info_a_pos = BufferInfo {
|
normalized: false,
|
||||||
location: a_pos_loc,
|
stride: 0,
|
||||||
vector_size: 2,
|
offset: 0,
|
||||||
data_type: glow::FLOAT,
|
}],
|
||||||
normalized: false,
|
);
|
||||||
stride: 0,
|
|
||||||
offset: 0,
|
|
||||||
};
|
|
||||||
vertex_array.add_new_attribute(&gl, buffer_info_a_pos);
|
|
||||||
|
|
||||||
let index_buffer = gl.create_buffer()?;
|
let index_buffer = gl.create_buffer()?;
|
||||||
gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(index_buffer));
|
gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(index_buffer));
|
||||||
|
|
@ -153,7 +148,7 @@ impl PostProcess {
|
||||||
gl,
|
gl,
|
||||||
pos_buffer,
|
pos_buffer,
|
||||||
index_buffer,
|
index_buffer,
|
||||||
vertex_array,
|
vao,
|
||||||
is_webgl_1,
|
is_webgl_1,
|
||||||
texture,
|
texture,
|
||||||
texture_size: (width, height),
|
texture_size: (width, height),
|
||||||
|
|
@ -212,13 +207,13 @@ impl PostProcess {
|
||||||
.get_uniform_location(self.program, "u_sampler")
|
.get_uniform_location(self.program, "u_sampler")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.gl.uniform_1_i32(Some(&u_sampler_loc), 0);
|
self.gl.uniform_1_i32(Some(&u_sampler_loc), 0);
|
||||||
self.vertex_array.bind_vertex_array(&self.gl);
|
self.vao.bind(&self.gl);
|
||||||
|
|
||||||
self.gl
|
self.gl
|
||||||
.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.index_buffer));
|
.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.index_buffer));
|
||||||
self.gl
|
self.gl
|
||||||
.draw_elements(glow::TRIANGLES, 6, glow::UNSIGNED_BYTE, 0);
|
.draw_elements(glow::TRIANGLES, 6, glow::UNSIGNED_BYTE, 0);
|
||||||
self.vertex_array.unbind_vertex_array(&self.gl);
|
self.vao.unbind(&self.gl);
|
||||||
self.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None);
|
self.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None);
|
||||||
self.gl.bind_texture(glow::TEXTURE_2D, None);
|
self.gl.bind_texture(glow::TEXTURE_2D, None);
|
||||||
self.gl.use_program(None);
|
self.gl.use_program(None);
|
||||||
|
|
|
||||||
|
|
@ -18,35 +18,67 @@ pub(crate) struct BufferInfo {
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
pub struct EmulatedVao {
|
/// Wrapper around either Emulated VAO or GL's VAO.
|
||||||
buffer: Option<glow::Buffer>,
|
pub(crate) struct VertexArrayObject {
|
||||||
|
// If `None`, we emulate VAO:s.
|
||||||
|
vao: Option<crate::glow::VertexArray>,
|
||||||
|
vbo: glow::Buffer,
|
||||||
buffer_infos: Vec<BufferInfo>,
|
buffer_infos: Vec<BufferInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EmulatedVao {
|
impl VertexArrayObject {
|
||||||
pub(crate) fn new() -> Self {
|
#[allow(clippy::needless_pass_by_value)] // false positive
|
||||||
|
pub(crate) unsafe fn new(
|
||||||
|
gl: &glow::Context,
|
||||||
|
vbo: glow::Buffer,
|
||||||
|
buffer_infos: Vec<BufferInfo>,
|
||||||
|
) -> Self {
|
||||||
|
let vao = if supports_vao(gl) {
|
||||||
|
let vao = gl.create_vertex_array().unwrap();
|
||||||
|
check_for_gl_error!(gl, "create_vertex_array");
|
||||||
|
|
||||||
|
// Store state in the VAO:
|
||||||
|
gl.bind_vertex_array(Some(vao));
|
||||||
|
gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo));
|
||||||
|
|
||||||
|
for attribute in &buffer_infos {
|
||||||
|
gl.vertex_attrib_pointer_f32(
|
||||||
|
attribute.location,
|
||||||
|
attribute.vector_size,
|
||||||
|
attribute.data_type,
|
||||||
|
attribute.normalized,
|
||||||
|
attribute.stride,
|
||||||
|
attribute.offset,
|
||||||
|
);
|
||||||
|
check_for_gl_error!(gl, "vertex_attrib_pointer_f32");
|
||||||
|
gl.enable_vertex_attrib_array(attribute.location);
|
||||||
|
check_for_gl_error!(gl, "enable_vertex_attrib_array");
|
||||||
|
}
|
||||||
|
|
||||||
|
gl.bind_vertex_array(None);
|
||||||
|
|
||||||
|
Some(vao)
|
||||||
|
} else {
|
||||||
|
tracing::debug!("VAO not supported");
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
buffer: None,
|
vao,
|
||||||
buffer_infos: vec![],
|
vbo,
|
||||||
|
buffer_infos,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn bind_buffer(&mut self, buffer: &glow::Buffer) {
|
pub(crate) unsafe fn bind(&self, gl: &glow::Context) {
|
||||||
let _old = self.buffer.replace(*buffer);
|
if let Some(vao) = self.vao {
|
||||||
}
|
gl.bind_vertex_array(Some(vao));
|
||||||
|
check_for_gl_error!(gl, "bind_vertex_array");
|
||||||
pub(crate) fn add_new_attribute(&mut self, buffer_info: BufferInfo) {
|
} else {
|
||||||
self.buffer_infos.push(buffer_info);
|
gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vbo));
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn bind_vertex_array(&self, gl: &glow::Context) {
|
|
||||||
unsafe {
|
|
||||||
gl.bind_buffer(glow::ARRAY_BUFFER, self.buffer);
|
|
||||||
check_for_gl_error!(gl, "bind_buffer");
|
check_for_gl_error!(gl, "bind_buffer");
|
||||||
}
|
|
||||||
for attribute in &self.buffer_infos {
|
for attribute in &self.buffer_infos {
|
||||||
dbg!(attribute);
|
|
||||||
unsafe {
|
|
||||||
gl.vertex_attrib_pointer_f32(
|
gl.vertex_attrib_pointer_f32(
|
||||||
attribute.location,
|
attribute.location,
|
||||||
attribute.vector_size,
|
attribute.vector_size,
|
||||||
|
|
@ -62,87 +94,21 @@ impl EmulatedVao {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn unbind_vertex_array(&self, gl: &glow::Context) {
|
pub(crate) unsafe fn unbind(&self, gl: &glow::Context) {
|
||||||
for attribute in &self.buffer_infos {
|
if self.vao.is_some() {
|
||||||
unsafe {
|
gl.bind_vertex_array(None);
|
||||||
|
} else {
|
||||||
|
gl.bind_buffer(glow::ARRAY_BUFFER, None);
|
||||||
|
for attribute in &self.buffer_infos {
|
||||||
gl.disable_vertex_attrib_array(attribute.location);
|
gl.disable_vertex_attrib_array(attribute.location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe {
|
|
||||||
gl.bind_buffer(glow::ARRAY_BUFFER, None);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Wrapper around either Emulated VAO and GL's VAO
|
fn supports_vao(gl: &glow::Context) -> bool {
|
||||||
pub(crate) enum VAO {
|
|
||||||
Emulated(crate::vao::EmulatedVao),
|
|
||||||
Native(crate::glow::VertexArray),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VAO {
|
|
||||||
pub(crate) unsafe fn native(gl: &glow::Context) -> Self {
|
|
||||||
Self::Native(gl.create_vertex_array().unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) unsafe fn emulated() -> Self {
|
|
||||||
Self::Emulated(crate::vao::EmulatedVao::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) unsafe fn bind_vertex_array(&self, gl: &glow::Context) {
|
|
||||||
match self {
|
|
||||||
VAO::Emulated(emulated_vao) => emulated_vao.bind_vertex_array(gl),
|
|
||||||
VAO::Native(vao) => {
|
|
||||||
gl.bind_vertex_array(Some(*vao));
|
|
||||||
check_for_gl_error!(gl, "bind_vertex_array");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) unsafe fn bind_buffer(&mut self, gl: &glow::Context, buffer: &glow::Buffer) {
|
|
||||||
match self {
|
|
||||||
VAO::Emulated(emulated_vao) => emulated_vao.bind_buffer(buffer),
|
|
||||||
VAO::Native(_) => gl.bind_buffer(glow::ARRAY_BUFFER, Some(*buffer)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) unsafe fn add_new_attribute(
|
|
||||||
&mut self,
|
|
||||||
gl: &glow::Context,
|
|
||||||
buffer_info: crate::vao::BufferInfo,
|
|
||||||
) {
|
|
||||||
match self {
|
|
||||||
VAO::Emulated(emulated_vao) => emulated_vao.add_new_attribute(buffer_info),
|
|
||||||
VAO::Native(_) => {
|
|
||||||
gl.vertex_attrib_pointer_f32(
|
|
||||||
buffer_info.location,
|
|
||||||
buffer_info.vector_size,
|
|
||||||
buffer_info.data_type,
|
|
||||||
buffer_info.normalized,
|
|
||||||
buffer_info.stride,
|
|
||||||
buffer_info.offset,
|
|
||||||
);
|
|
||||||
gl.enable_vertex_attrib_array(buffer_info.location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) unsafe fn unbind_vertex_array(&self, gl: &glow::Context) {
|
|
||||||
match self {
|
|
||||||
VAO::Emulated(emulated_vao) => emulated_vao.unbind_vertex_array(gl),
|
|
||||||
VAO::Native(_) => {
|
|
||||||
gl.bind_vertex_array(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// If returned true no need to emulate vao
|
|
||||||
pub(crate) fn supports_vao(gl: &glow::Context) -> bool {
|
|
||||||
const WEBGL_PREFIX: &str = "WebGL ";
|
const WEBGL_PREFIX: &str = "WebGL ";
|
||||||
const OPENGL_ES_PREFIX: &str = "OpenGL ES ";
|
const OPENGL_ES_PREFIX: &str = "OpenGL ES ";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,10 @@ pub use {
|
||||||
image::{AlphaImage, ColorImage, ImageData, ImageDelta},
|
image::{AlphaImage, ColorImage, ImageData, ImageDelta},
|
||||||
mesh::{Mesh, Mesh16, Vertex},
|
mesh::{Mesh, Mesh16, Vertex},
|
||||||
shadow::Shadow,
|
shadow::Shadow,
|
||||||
shape::{CircleShape, PaintCallback, PathShape, RectShape, Rounding, Shape, TextShape},
|
shape::{
|
||||||
|
CircleShape, PaintCallback, PaintCallbackInfo, PathShape, RectShape, Rounding, Shape,
|
||||||
|
TextShape,
|
||||||
|
},
|
||||||
stats::PaintStats,
|
stats::PaintStats,
|
||||||
stroke::Stroke,
|
stroke::Stroke,
|
||||||
tessellator::{tessellate_shapes, TessellationOptions, Tessellator},
|
tessellator::{tessellate_shapes, TessellationOptions, Tessellator},
|
||||||
|
|
|
||||||
|
|
@ -642,6 +642,52 @@ fn dashes_from_line(
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Information passed along with [`PaintCallback`] ([`Shape::Callback`]).
|
||||||
|
pub struct PaintCallbackInfo {
|
||||||
|
/// Viewport in points.
|
||||||
|
pub rect: Rect,
|
||||||
|
|
||||||
|
/// Pixels per point.
|
||||||
|
pub pixels_per_point: f32,
|
||||||
|
|
||||||
|
/// Full size of the screen, in pixels.
|
||||||
|
pub screen_size_px: [u32; 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PaintCallbackInfo {
|
||||||
|
/// Physical pixel offset for left side of the viewport.
|
||||||
|
#[inline]
|
||||||
|
pub fn viewport_left_px(&self) -> f32 {
|
||||||
|
self.rect.min.x * self.pixels_per_point
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Physical pixel offset for top side of the viewport.
|
||||||
|
#[inline]
|
||||||
|
pub fn viewport_top_px(&self) -> f32 {
|
||||||
|
self.rect.min.y * self.pixels_per_point
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Physical pixel offset for bottom side of the viewport.
|
||||||
|
///
|
||||||
|
/// This is what `glViewport` etc expects for the y axis.
|
||||||
|
#[inline]
|
||||||
|
pub fn viewport_from_bottom_px(&self) -> f32 {
|
||||||
|
self.screen_size_px[1] as f32 - self.rect.max.y * self.pixels_per_point
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Viewport width in physical pixels.
|
||||||
|
#[inline]
|
||||||
|
pub fn viewport_width_px(&self) -> f32 {
|
||||||
|
self.rect.width() * self.pixels_per_point
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Viewport width in physical pixels.
|
||||||
|
#[inline]
|
||||||
|
pub fn viewport_height_px(&self) -> f32 {
|
||||||
|
self.rect.height() * self.pixels_per_point
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// If you want to paint some 3D shapes inside an egui region, you can use this.
|
/// If you want to paint some 3D shapes inside an egui region, you can use this.
|
||||||
///
|
///
|
||||||
/// This is advanced usage, and is backend specific.
|
/// This is advanced usage, and is backend specific.
|
||||||
|
|
@ -650,21 +696,22 @@ pub struct PaintCallback {
|
||||||
/// Where to paint.
|
/// Where to paint.
|
||||||
pub rect: Rect,
|
pub rect: Rect,
|
||||||
|
|
||||||
/// Paint something custom using.
|
/// Paint something custom (e.g. 3D stuff).
|
||||||
///
|
///
|
||||||
/// The argument is the render context, and what it contains depends on the backend.
|
/// The argument is the render context, and what it contains depends on the backend.
|
||||||
/// In `eframe` it will be `egui_glow::Painter`.
|
/// In `eframe` it will be `egui_glow::Painter`.
|
||||||
///
|
///
|
||||||
/// The rendering backend is responsible for first setting the active viewport to [`Self::rect`].
|
/// The rendering backend is responsible for first setting the active viewport to [`Self::rect`].
|
||||||
/// The rendering backend is also responsible for restoring any state it needs,
|
///
|
||||||
|
/// The rendering backend is also responsible for restoring any state,
|
||||||
/// such as the bound shader program and vertex array.
|
/// such as the bound shader program and vertex array.
|
||||||
pub callback: std::sync::Arc<dyn Fn(&dyn std::any::Any) + Send + Sync>,
|
pub callback: std::sync::Arc<dyn Fn(&PaintCallbackInfo, &dyn std::any::Any) + Send + Sync>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PaintCallback {
|
impl PaintCallback {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn call(&self, render_ctx: &dyn std::any::Any) {
|
pub fn call(&self, info: &PaintCallbackInfo, render_ctx: &dyn std::any::Any) {
|
||||||
(self.callback)(render_ctx);
|
(self.callback)(info, render_ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue