summaryrefslogtreecommitdiffstats
path: root/glow/src/quad.rs
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-05-19 14:23:28 +0200
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-05-19 14:23:28 +0200
commitd4743183d40c6044ce6fa39e2a52919a32912cda (patch)
treed2dec81cd9b419262cf2aa57ad793895ccacb320 /glow/src/quad.rs
parent33448508a524db6447b380cc236be6f0d5ca8a86 (diff)
downloadiced-d4743183d40c6044ce6fa39e2a52919a32912cda.tar.gz
iced-d4743183d40c6044ce6fa39e2a52919a32912cda.tar.bz2
iced-d4743183d40c6044ce6fa39e2a52919a32912cda.zip
Draft first working version of `iced_glow` :tada:
Diffstat (limited to 'glow/src/quad.rs')
-rw-r--r--glow/src/quad.rs254
1 files changed, 254 insertions, 0 deletions
diff --git a/glow/src/quad.rs b/glow/src/quad.rs
new file mode 100644
index 00000000..744597d2
--- /dev/null
+++ b/glow/src/quad.rs
@@ -0,0 +1,254 @@
+use crate::{Transformation, Viewport};
+use glow::HasContext;
+use iced_native::Rectangle;
+
+#[derive(Debug)]
+pub struct Pipeline {
+ program: <glow::Context as HasContext>::Program,
+ vertex_array: <glow::Context as HasContext>::VertexArray,
+ instances: <glow::Context as HasContext>::Buffer,
+ current_transform: Transformation,
+ current_scale: f32,
+}
+
+impl Pipeline {
+ pub fn new(gl: &glow::Context) -> Pipeline {
+ let program = unsafe {
+ create_program(
+ gl,
+ &[
+ (glow::VERTEX_SHADER, include_str!("shader/quad.vert")),
+ (glow::FRAGMENT_SHADER, include_str!("shader/quad.frag")),
+ ],
+ )
+ };
+
+ unsafe {
+ gl.use_program(Some(program));
+
+ gl.uniform_matrix_4_f32_slice(
+ Some(0),
+ false,
+ &Transformation::identity().into(),
+ );
+ gl.uniform_1_f32(Some(1), 1.0);
+
+ gl.use_program(None);
+ }
+
+ let (vertex_array, instances) =
+ unsafe { create_instance_buffer(gl, Quad::MAX) };
+
+ Pipeline {
+ program,
+ vertex_array,
+ instances,
+ current_transform: Transformation::identity(),
+ current_scale: 1.0,
+ }
+ }
+
+ pub fn draw(
+ &mut self,
+ gl: &glow::Context,
+ viewport: &Viewport,
+ instances: &[Quad],
+ transformation: Transformation,
+ scale: f32,
+ bounds: Rectangle<u32>,
+ ) {
+ unsafe {
+ gl.enable(glow::SCISSOR_TEST);
+ gl.scissor(
+ bounds.x as i32,
+ (viewport.height()
+ - (bounds.y + bounds.height).min(viewport.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 {
+ gl.uniform_matrix_4_f32_slice(
+ Some(0),
+ false,
+ &transformation.into(),
+ );
+
+ self.current_transform = transformation;
+ }
+ }
+
+ if scale != self.current_scale {
+ unsafe {
+ gl.uniform_1_f32(Some(1), scale);
+ }
+
+ self.current_scale = scale;
+ }
+
+ let mut i = 0;
+ let total = instances.len();
+
+ while i < total {
+ let end = (i + Quad::MAX).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 += Quad::MAX;
+ }
+
+ unsafe {
+ gl.bind_vertex_array(None);
+ gl.use_program(None);
+ gl.disable(glow::SCISSOR_TEST);
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct Quad {
+ pub position: [f32; 2],
+ pub scale: [f32; 2],
+ pub color: [f32; 4],
+ pub border_color: [f32; 4],
+ pub border_radius: f32,
+ pub border_width: f32,
+}
+
+unsafe impl bytemuck::Zeroable for Quad {}
+unsafe impl bytemuck::Pod for Quad {}
+
+impl Quad {
+ const MAX: usize = 100_000;
+}
+
+unsafe fn create_program(
+ gl: &glow::Context,
+ shader_sources: &[(u32, &str)],
+) -> <glow::Context as HasContext>::Program {
+ let program = gl.create_program().expect("Cannot create program");
+
+ let mut shaders = Vec::with_capacity(shader_sources.len());
+
+ for (shader_type, shader_source) in shader_sources.iter() {
+ let shader = gl
+ .create_shader(*shader_type)
+ .expect("Cannot create shader");
+
+ gl.shader_source(shader, shader_source);
+ gl.compile_shader(shader);
+
+ if !gl.get_shader_compile_status(shader) {
+ panic!(gl.get_shader_info_log(shader));
+ }
+
+ gl.attach_shader(program, shader);
+
+ shaders.push(shader);
+ }
+
+ gl.link_program(program);
+ if !gl.get_program_link_status(program) {
+ panic!(gl.get_program_info_log(program));
+ }
+
+ for shader in shaders {
+ gl.detach_shader(program, shader);
+ gl.delete_shader(shader);
+ }
+
+ program
+}
+
+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::<Quad>()) as i32,
+ glow::DYNAMIC_DRAW,
+ );
+
+ let stride = std::mem::size_of::<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)
+}