summaryrefslogtreecommitdiffstats
path: root/glow/src/triangle.rs
diff options
context:
space:
mode:
Diffstat (limited to 'glow/src/triangle.rs')
-rw-r--r--glow/src/triangle.rs228
1 files changed, 117 insertions, 111 deletions
diff --git a/glow/src/triangle.rs b/glow/src/triangle.rs
index ae4f83ef..7d0e14c7 100644
--- a/glow/src/triangle.rs
+++ b/glow/src/triangle.rs
@@ -1,66 +1,41 @@
-//! Draw meshes of triangles.
+//! Draw meshes of triangle.
+mod gradient;
+mod solid;
+
use crate::program::{self, Shader};
use crate::Transformation;
use glow::HasContext;
-use iced_graphics::layer;
+use iced_graphics::layer::{Mesh, Meshes};
+use iced_graphics::shader;
use std::marker::PhantomData;
+use crate::triangle::gradient::GradientProgram;
+use crate::triangle::solid::SolidProgram;
pub use iced_graphics::triangle::{Mesh2D, Vertex2D};
-const VERTEX_BUFFER_SIZE: usize = 10_000;
-const INDEX_BUFFER_SIZE: usize = 10_000;
-
#[derive(Debug)]
pub(crate) struct Pipeline {
- program: <glow::Context as HasContext>::Program,
vertex_array: <glow::Context as HasContext>::VertexArray,
vertices: Buffer<Vertex2D>,
indices: Buffer<u32>,
- transform_location: <glow::Context as HasContext>::UniformLocation,
current_transform: Transformation,
+ programs: TrianglePrograms,
}
-impl Pipeline {
- pub fn new(
- gl: &glow::Context,
- shader_version: &program::Version,
- ) -> Pipeline {
- let program = unsafe {
- let vertex_shader = Shader::vertex(
- gl,
- shader_version,
- include_str!("shader/common/triangle.vert"),
- );
- let fragment_shader = Shader::fragment(
- gl,
- shader_version,
- include_str!("shader/common/triangle.frag"),
- );
-
- program::create(
- gl,
- &[vertex_shader, fragment_shader],
- &[(0, "i_Position"), (1, "i_Color")],
- )
- };
-
- let transform_location =
- unsafe { gl.get_uniform_location(program, "u_Transform") }
- .expect("Get transform location");
-
- unsafe {
- gl.use_program(Some(program));
-
- let transform: [f32; 16] = Transformation::identity().into();
- gl.uniform_matrix_4_f32_slice(
- Some(&transform_location),
- false,
- &transform,
- );
+#[derive(Debug)]
+struct TrianglePrograms {
+ solid: TriangleProgram,
+ gradient: TriangleProgram,
+}
- gl.use_program(None);
- }
+#[derive(Debug)]
+enum TriangleProgram {
+ Solid(SolidProgram),
+ Gradient(GradientProgram),
+}
+impl Pipeline {
+ pub fn new(gl: &glow::Context, shader_version: &program::Version) -> Self {
let vertex_array =
unsafe { gl.create_vertex_array().expect("Create vertex array") };
@@ -73,7 +48,7 @@ impl Pipeline {
gl,
glow::ARRAY_BUFFER,
glow::DYNAMIC_DRAW,
- VERTEX_BUFFER_SIZE,
+ std::mem::size_of::<Vertex2D>() as usize,
)
};
@@ -82,7 +57,7 @@ impl Pipeline {
gl,
glow::ELEMENT_ARRAY_BUFFER,
glow::DYNAMIC_DRAW,
- INDEX_BUFFER_SIZE,
+ std::mem::size_of::<u32>() as usize,
)
};
@@ -92,58 +67,45 @@ impl Pipeline {
gl.enable_vertex_attrib_array(0);
gl.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, stride, 0);
- gl.enable_vertex_attrib_array(1);
- gl.vertex_attrib_pointer_f32(
- 1,
- 4,
- glow::FLOAT,
- false,
- stride,
- 4 * 2,
- );
-
gl.bind_vertex_array(None);
- }
+ };
- Pipeline {
- program,
+ Self {
vertex_array,
vertices,
indices,
- transform_location,
current_transform: Transformation::identity(),
+ programs: TrianglePrograms {
+ solid: TriangleProgram::Solid(SolidProgram::new(
+ gl,
+ shader_version,
+ )),
+ gradient: TriangleProgram::Gradient(GradientProgram::new(
+ gl,
+ shader_version,
+ )),
+ },
}
}
pub fn draw(
&mut self,
+ meshes: &Meshes<'_>,
gl: &glow::Context,
target_height: u32,
transformation: Transformation,
scale_factor: f32,
- meshes: &[layer::Mesh<'_>],
) {
unsafe {
gl.enable(glow::MULTISAMPLE);
gl.enable(glow::SCISSOR_TEST);
- gl.use_program(Some(self.program));
- gl.bind_vertex_array(Some(self.vertex_array));
+ gl.bind_vertex_array(Some(self.vertex_array))
}
- // This looks a bit crazy, but we are just counting how many vertices
- // and indices we will need to handle.
- // TODO: Improve readability
- let (total_vertices, total_indices) = meshes
- .iter()
- .map(|layer::Mesh { buffers, .. }| {
- (buffers.vertices.len(), buffers.indices.len())
- })
- .fold((0, 0), |(total_v, total_i), (v, i)| {
- (total_v + v, total_i + i)
- });
-
- // Then we ensure the current buffers are big enough, resizing if
- // necessary
+ //count the total number of vertices & indices we need to handle for all meshes
+ let (total_vertices, total_indices) = meshes.attribute_count();
+
+ // Then we ensure the current attribute buffers are big enough, resizing if necessary
unsafe {
self.vertices.bind(gl, total_vertices);
self.indices.bind(gl, total_indices);
@@ -153,7 +115,7 @@ impl Pipeline {
let mut last_vertex = 0;
let mut last_index = 0;
- for layer::Mesh { buffers, .. } in meshes {
+ for Mesh { buffers, .. } in meshes.0.iter() {
unsafe {
gl.buffer_sub_data_u8_slice(
glow::ARRAY_BUFFER,
@@ -176,11 +138,12 @@ impl Pipeline {
let mut last_vertex = 0;
let mut last_index = 0;
- for layer::Mesh {
+ for Mesh {
buffers,
origin,
clip_bounds,
- } in meshes
+ shader,
+ } in meshes.0.iter()
{
let transform =
transformation * Transformation::translate(origin.x, origin.y);
@@ -188,17 +151,6 @@ impl Pipeline {
let clip_bounds = (*clip_bounds * scale_factor).snap();
unsafe {
- if self.current_transform != transform {
- let matrix: [f32; 16] = transform.into();
- gl.uniform_matrix_4_f32_slice(
- Some(&self.transform_location),
- false,
- &matrix,
- );
-
- self.current_transform = transform;
- }
-
gl.scissor(
clip_bounds.x as i32,
(target_height - (clip_bounds.y + clip_bounds.height))
@@ -207,6 +159,15 @@ impl Pipeline {
clip_bounds.height as i32,
);
+ let t = if self.current_transform != transform {
+ self.current_transform = transform;
+ Some(transform)
+ } else {
+ None
+ };
+
+ self.use_with_shader(gl, shader, t);
+
gl.draw_elements_base_vertex(
glow::TRIANGLES,
buffers.indices.len() as i32,
@@ -222,34 +183,79 @@ impl Pipeline {
unsafe {
gl.bind_vertex_array(None);
- gl.use_program(None);
gl.disable(glow::SCISSOR_TEST);
gl.disable(glow::MULTISAMPLE);
}
}
-}
-#[repr(C)]
-#[derive(Debug, Clone, Copy)]
-struct Uniforms {
- transform: [f32; 16],
+ fn use_with_shader(
+ &mut self,
+ gl: &glow::Context,
+ shader: &shader::Shader,
+ transform: Option<Transformation>,
+ ) {
+ match shader {
+ shader::Shader::Solid(color) => {
+ if let TriangleProgram::Solid(solid_program) =
+ &mut self.programs.solid
+ {
+ unsafe { gl.use_program(Some(solid_program.program)) }
+ solid_program.set_uniforms(gl, color, transform);
+ }
+ }
+ shader::Shader::Gradient(gradient) => {
+ if let TriangleProgram::Gradient(gradient_program) =
+ &mut self.programs.gradient
+ {
+ unsafe { gl.use_program(Some(gradient_program.program)) }
+ gradient_program.set_uniforms(gl, gradient, transform);
+ }
+ }
+ }
+ }
}
-unsafe impl bytemuck::Zeroable for Uniforms {}
-unsafe impl bytemuck::Pod for Uniforms {}
-
-impl Default for Uniforms {
- fn default() -> Self {
- Self {
- transform: *Transformation::identity().as_ref(),
- }
+/// A simple shader program. Uses [`triangle.vert`] for its vertex shader and only binds position
+/// attribute location.
+pub(super) fn simple_triangle_program(
+ gl: &glow::Context,
+ shader_version: &program::Version,
+ fragment_shader: &'static str,
+) -> <glow::Context as HasContext>::Program {
+ unsafe {
+ let vertex_shader = Shader::vertex(
+ gl,
+ shader_version,
+ include_str!("shader/common/triangle.vert"),
+ );
+
+ let fragment_shader =
+ Shader::fragment(gl, shader_version, fragment_shader);
+
+ program::create(
+ gl,
+ &[vertex_shader, fragment_shader],
+ &[(0, "i_Position")],
+ )
}
}
-impl From<Transformation> for Uniforms {
- fn from(transformation: Transformation) -> Uniforms {
- Self {
- transform: transformation.into(),
+pub(super) fn update_transform(
+ gl: &glow::Context,
+ program: <glow::Context as HasContext>::Program,
+ transform: Option<Transformation>
+) {
+ if let Some(t) = transform {
+ let transform_location =
+ unsafe { gl.get_uniform_location(program, "u_Transform") }
+ .expect("Get transform location.");
+
+ unsafe {
+ gl.uniform_matrix_4_f32_slice(
+ Some(&transform_location),
+ false,
+ t.as_ref(),
+ );
}
}
}