summaryrefslogtreecommitdiffstats
path: root/glow/src/quad.rs
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón <hector0193@gmail.com>2020-05-28 21:52:34 +0200
committerLibravatar GitHub <noreply@github.com>2020-05-28 21:52:34 +0200
commitd3db055583f4cbef1441fd66d07da70424bd1200 (patch)
tree9f695bd26f688a5aaf3b8fa687a0e3ff096ffe11 /glow/src/quad.rs
parentead4186870d1b46015986f702dd63382498060fc (diff)
parent709ed1f3f7ad8cf67a176763e394aaae4e808e93 (diff)
downloadiced-d3db055583f4cbef1441fd66d07da70424bd1200.tar.gz
iced-d3db055583f4cbef1441fd66d07da70424bd1200.tar.bz2
iced-d3db055583f4cbef1441fd66d07da70424bd1200.zip
Merge pull request #354 from hecrj/feature/glow-renderer
OpenGL renderer and backend-agnostic graphics subcrate
Diffstat (limited to 'glow/src/quad.rs')
-rw-r--r--glow/src/quad.rs235
1 files changed, 235 insertions, 0 deletions
diff --git a/glow/src/quad.rs b/glow/src/quad.rs
new file mode 100644
index 00000000..3a65338a
--- /dev/null
+++ b/glow/src/quad.rs
@@ -0,0 +1,235 @@
+use crate::program;
+use crate::Transformation;
+use glow::HasContext;
+use iced_graphics::layer;
+use iced_native::Rectangle;
+
+const MAX_INSTANCES: usize = 100_000;
+
+#[derive(Debug)]
+pub struct Pipeline {
+ program: <glow::Context as HasContext>::Program,
+ vertex_array: <glow::Context as HasContext>::VertexArray,
+ instances: <glow::Context as HasContext>::Buffer,
+ transform_location: <glow::Context as HasContext>::UniformLocation,
+ scale_location: <glow::Context as HasContext>::UniformLocation,
+ screen_height_location: <glow::Context as HasContext>::UniformLocation,
+ current_transform: Transformation,
+ current_scale: f32,
+ current_target_height: u32,
+}
+
+impl Pipeline {
+ pub fn new(gl: &glow::Context) -> Pipeline {
+ let program = unsafe {
+ program::create(
+ gl,
+ &[
+ (glow::VERTEX_SHADER, include_str!("shader/quad.vert")),
+ (glow::FRAGMENT_SHADER, include_str!("shader/quad.frag")),
+ ],
+ )
+ };
+
+ let transform_location =
+ unsafe { gl.get_uniform_location(program, "u_Transform") }
+ .expect("Get transform location");
+
+ let scale_location =
+ unsafe { gl.get_uniform_location(program, "u_Scale") }
+ .expect("Get scale location");
+
+ let screen_height_location =
+ unsafe { gl.get_uniform_location(program, "u_ScreenHeight") }
+ .expect("Get target height location");
+
+ unsafe {
+ gl.use_program(Some(program));
+
+ let matrix: [f32; 16] = Transformation::identity().into();
+ gl.uniform_matrix_4_f32_slice(
+ Some(transform_location),
+ false,
+ &matrix,
+ );
+
+ gl.uniform_1_f32(Some(scale_location), 1.0);
+ gl.uniform_1_f32(Some(screen_height_location), 0.0);
+
+ gl.use_program(None);
+ }
+
+ let (vertex_array, instances) =
+ unsafe { create_instance_buffer(gl, MAX_INSTANCES) };
+
+ Pipeline {
+ program,
+ vertex_array,
+ instances,
+ transform_location,
+ scale_location,
+ screen_height_location,
+ current_transform: Transformation::identity(),
+ current_scale: 1.0,
+ current_target_height: 0,
+ }
+ }
+
+ pub fn draw(
+ &mut self,
+ gl: &glow::Context,
+ target_height: u32,
+ instances: &[layer::Quad],
+ transformation: Transformation,
+ scale: f32,
+ bounds: Rectangle<u32>,
+ ) {
+ unsafe {
+ gl.enable(glow::SCISSOR_TEST);
+ gl.scissor(
+ bounds.x as i32,
+ (target_height - (bounds.y + bounds.height)) as i32,
+ bounds.width as i32,
+ bounds.height as i32,
+ );
+
+ gl.use_program(Some(self.program));
+ gl.bind_vertex_array(Some(self.vertex_array));
+ gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.instances));
+ }
+
+ if transformation != self.current_transform {
+ unsafe {
+ let matrix: [f32; 16] = transformation.into();
+ gl.uniform_matrix_4_f32_slice(
+ Some(self.transform_location),
+ false,
+ &matrix,
+ );
+
+ self.current_transform = transformation;
+ }
+ }
+
+ if scale != self.current_scale {
+ unsafe {
+ gl.uniform_1_f32(Some(self.scale_location), scale);
+ }
+
+ self.current_scale = scale;
+ }
+
+ if target_height != self.current_target_height {
+ unsafe {
+ gl.uniform_1_f32(
+ Some(self.screen_height_location),
+ target_height as f32,
+ );
+ }
+
+ self.current_target_height = target_height;
+ }
+
+ let mut i = 0;
+ let total = instances.len();
+
+ while i < total {
+ let end = (i + MAX_INSTANCES).min(total);
+ let amount = end - i;
+
+ unsafe {
+ gl.buffer_sub_data_u8_slice(
+ glow::ARRAY_BUFFER,
+ 0,
+ bytemuck::cast_slice(&instances[i..end]),
+ );
+
+ gl.draw_arrays_instanced(
+ glow::TRIANGLE_STRIP,
+ 0,
+ 4,
+ amount as i32,
+ );
+ }
+
+ i += MAX_INSTANCES;
+ }
+
+ unsafe {
+ gl.bind_vertex_array(None);
+ gl.use_program(None);
+ gl.disable(glow::SCISSOR_TEST);
+ }
+ }
+}
+
+unsafe fn create_instance_buffer(
+ gl: &glow::Context,
+ size: usize,
+) -> (
+ <glow::Context as HasContext>::VertexArray,
+ <glow::Context as HasContext>::Buffer,
+) {
+ let vertex_array = gl.create_vertex_array().expect("Create vertex array");
+ let buffer = gl.create_buffer().expect("Create instance buffer");
+
+ gl.bind_vertex_array(Some(vertex_array));
+ gl.bind_buffer(glow::ARRAY_BUFFER, Some(buffer));
+ gl.buffer_data_size(
+ glow::ARRAY_BUFFER,
+ (size * std::mem::size_of::<layer::Quad>()) as i32,
+ glow::DYNAMIC_DRAW,
+ );
+
+ let stride = std::mem::size_of::<layer::Quad>() as i32;
+
+ gl.enable_vertex_attrib_array(0);
+ gl.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, stride, 0);
+ gl.vertex_attrib_divisor(0, 1);
+
+ gl.enable_vertex_attrib_array(1);
+ gl.vertex_attrib_pointer_f32(1, 2, glow::FLOAT, false, stride, 4 * 2);
+ gl.vertex_attrib_divisor(1, 1);
+
+ gl.enable_vertex_attrib_array(2);
+ gl.vertex_attrib_pointer_f32(2, 4, glow::FLOAT, false, stride, 4 * (2 + 2));
+ gl.vertex_attrib_divisor(2, 1);
+
+ gl.enable_vertex_attrib_array(3);
+ gl.vertex_attrib_pointer_f32(
+ 3,
+ 4,
+ glow::FLOAT,
+ false,
+ stride,
+ 4 * (2 + 2 + 4),
+ );
+ gl.vertex_attrib_divisor(3, 1);
+
+ gl.enable_vertex_attrib_array(4);
+ gl.vertex_attrib_pointer_f32(
+ 4,
+ 1,
+ glow::FLOAT,
+ false,
+ stride,
+ 4 * (2 + 2 + 4 + 4),
+ );
+ gl.vertex_attrib_divisor(4, 1);
+
+ gl.enable_vertex_attrib_array(5);
+ gl.vertex_attrib_pointer_f32(
+ 5,
+ 1,
+ glow::FLOAT,
+ false,
+ stride,
+ 4 * (2 + 2 + 4 + 4 + 1),
+ );
+ gl.vertex_attrib_divisor(5, 1);
+
+ gl.bind_vertex_array(None);
+ gl.bind_buffer(glow::ARRAY_BUFFER, None);
+
+ (vertex_array, buffer)
+}