Group all solid triangles independently of color

This commit is contained in:
Héctor Ramón Jiménez 2022-11-14 00:02:42 +01:00
parent 5b0dfcd0b0
commit 33c3c0c0aa
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
23 changed files with 1343 additions and 1084 deletions

View file

@ -11,8 +11,8 @@ out vec4 fragColor;
#define gl_FragColor fragColor
#endif
uniform vec4 color;
in vec4 v_Color;
void main() {
gl_FragColor = color;
gl_FragColor = v_Color;
}

View file

@ -0,0 +1,11 @@
uniform mat4 u_Transform;
in vec2 i_Position;
in vec4 i_Color;
out vec4 v_Color;
void main() {
gl_Position = u_Transform * vec4(i_Position, 0.0, 1.0);
v_Color = i_Color;
}

View file

@ -1,74 +1,49 @@
//! Draw meshes of triangles.
mod gradient;
mod solid;
use crate::program;
use crate::Transformation;
use iced_graphics::gradient::Gradient;
use iced_graphics::layer::mesh::{self, Mesh};
use iced_graphics::triangle::{self, Vertex2D};
use iced_graphics::triangle::{ColoredVertex2D, Vertex2D};
use glow::HasContext;
use std::marker::PhantomData;
#[derive(Debug)]
pub(crate) struct Pipeline {
vertex_array: <glow::Context as HasContext>::VertexArray,
vertices: Buffer<Vertex2D>,
indices: Buffer<u32>,
programs: ProgramList,
}
#[derive(Debug)]
struct ProgramList {
solid: solid::Program,
gradient: gradient::Program,
}
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") };
unsafe {
gl.bind_vertex_array(Some(vertex_array));
}
let vertices = unsafe {
Buffer::new(
gl,
glow::ARRAY_BUFFER,
glow::DYNAMIC_DRAW,
std::mem::size_of::<Vertex2D>() as usize,
)
};
let indices = unsafe {
let mut indices = unsafe {
Buffer::new(
gl,
glow::ELEMENT_ARRAY_BUFFER,
glow::DYNAMIC_DRAW,
std::mem::size_of::<u32>() as usize,
1000,
)
};
unsafe {
let stride = std::mem::size_of::<Vertex2D>() as i32;
let solid = solid::Program::new(gl, shader_version);
let gradient = gradient::Program::new(gl, shader_version);
gl.enable_vertex_attrib_array(0);
gl.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, stride, 0);
unsafe {
gl.bind_vertex_array(Some(solid.vertex_array));
indices.bind(gl, 0);
gl.bind_vertex_array(Some(gradient.vertex_array));
indices.bind(gl, 0);
gl.bind_vertex_array(None);
};
}
Self {
vertex_array,
vertices,
indices,
programs: ProgramList {
solid: solid::Program::new(gl, shader_version),
gradient: gradient::Program::new(gl, shader_version),
},
solid,
gradient,
}
}
@ -83,50 +58,83 @@ impl Pipeline {
unsafe {
gl.enable(glow::MULTISAMPLE);
gl.enable(glow::SCISSOR_TEST);
gl.bind_vertex_array(Some(self.vertex_array))
}
//count the total amount of vertices & indices we need to handle
let (total_vertices, total_indices) = mesh::attribute_count_of(meshes);
// Count the total amount of vertices & indices we need to handle
let count = mesh::attribute_count_of(meshes);
// 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);
self.indices.bind(gl, count.indices);
}
// We upload all the vertices and indices upfront
let mut vertex_offset = 0;
let mut solid_vertex_offset = 0;
let mut gradient_vertex_offset = 0;
let mut index_offset = 0;
for mesh in meshes {
unsafe {
gl.buffer_sub_data_u8_slice(
glow::ARRAY_BUFFER,
(vertex_offset * std::mem::size_of::<Vertex2D>()) as i32,
bytemuck::cast_slice(&mesh.buffers.vertices),
);
let indices = mesh.indices();
unsafe {
gl.buffer_sub_data_u8_slice(
glow::ELEMENT_ARRAY_BUFFER,
(index_offset * std::mem::size_of::<u32>()) as i32,
bytemuck::cast_slice(&mesh.buffers.indices),
bytemuck::cast_slice(indices),
);
vertex_offset += mesh.buffers.vertices.len();
index_offset += mesh.buffers.indices.len();
index_offset += indices.len();
}
match mesh {
Mesh::Solid { buffers, .. } => {
unsafe {
self.solid.vertices.bind(gl, count.solid_vertices);
gl.buffer_sub_data_u8_slice(
glow::ARRAY_BUFFER,
(solid_vertex_offset
* std::mem::size_of::<ColoredVertex2D>())
as i32,
bytemuck::cast_slice(&buffers.vertices),
);
}
solid_vertex_offset += buffers.vertices.len();
}
Mesh::Gradient { buffers, .. } => {
unsafe {
self.gradient
.vertices
.bind(gl, count.gradient_vertices);
gl.buffer_sub_data_u8_slice(
glow::ARRAY_BUFFER,
(gradient_vertex_offset
* std::mem::size_of::<Vertex2D>())
as i32,
bytemuck::cast_slice(&buffers.vertices),
);
}
gradient_vertex_offset += buffers.vertices.len();
}
}
}
// Then we draw each mesh using offsets
let mut last_vertex = 0;
let mut last_solid_vertex = 0;
let mut last_gradient_vertex = 0;
let mut last_index = 0;
for mesh in meshes {
let transform = transformation
* Transformation::translate(mesh.origin.x, mesh.origin.y);
let indices = mesh.indices();
let origin = mesh.origin();
let clip_bounds = (mesh.clip_bounds * scale_factor).snap();
let transform =
transformation * Transformation::translate(origin.x, origin.y);
let clip_bounds = (mesh.clip_bounds() * scale_factor).snap();
unsafe {
gl.scissor(
@ -136,30 +144,126 @@ impl Pipeline {
clip_bounds.width as i32,
clip_bounds.height as i32,
);
match mesh.style {
triangle::Style::Solid(color) => {
self.programs.solid.use_program(gl, color, &transform);
}
#[cfg(not(target_arch = "wasm32"))]
triangle::Style::Gradient(gradient) => {
self.programs
.gradient
.use_program(gl, gradient, &transform);
}
}
gl.draw_elements_base_vertex(
glow::TRIANGLES,
mesh.buffers.indices.len() as i32,
glow::UNSIGNED_INT,
(last_index * std::mem::size_of::<u32>()) as i32,
last_vertex as i32,
);
last_vertex += mesh.buffers.vertices.len();
last_index += mesh.buffers.indices.len();
}
match mesh {
Mesh::Solid { buffers, .. } => unsafe {
gl.use_program(Some(self.solid.program));
gl.bind_vertex_array(Some(self.solid.vertex_array));
if transform != self.solid.uniforms.transform {
gl.uniform_matrix_4_f32_slice(
Some(&self.solid.uniforms.transform_location),
false,
transform.as_ref(),
);
self.solid.uniforms.transform = transform;
}
gl.draw_elements_base_vertex(
glow::TRIANGLES,
indices.len() as i32,
glow::UNSIGNED_INT,
(last_index * std::mem::size_of::<u32>()) as i32,
last_solid_vertex as i32,
);
last_solid_vertex += buffers.vertices.len();
},
Mesh::Gradient {
buffers, gradient, ..
} => unsafe {
gl.use_program(Some(self.gradient.program));
gl.bind_vertex_array(Some(self.gradient.vertex_array));
if transform != self.gradient.uniforms.transform {
gl.uniform_matrix_4_f32_slice(
Some(&self.gradient.uniforms.locations.transform),
false,
transform.as_ref(),
);
self.gradient.uniforms.transform = transform;
}
if &self.gradient.uniforms.gradient != *gradient {
match gradient {
Gradient::Linear(linear) => {
gl.uniform_4_f32(
Some(
&self
.gradient
.uniforms
.locations
.gradient_direction,
),
linear.start.x,
linear.start.y,
linear.end.x,
linear.end.y,
);
gl.uniform_1_i32(
Some(
&self
.gradient
.uniforms
.locations
.color_stops_size,
),
(linear.color_stops.len() * 2) as i32,
);
let mut stops = [0.0; 128];
for (index, stop) in linear
.color_stops
.iter()
.enumerate()
.take(16)
{
let [r, g, b, a] = stop.color.into_linear();
stops[index * 8] = r;
stops[(index * 8) + 1] = g;
stops[(index * 8) + 2] = b;
stops[(index * 8) + 3] = a;
stops[(index * 8) + 4] = stop.offset;
stops[(index * 8) + 5] = 0.;
stops[(index * 8) + 6] = 0.;
stops[(index * 8) + 7] = 0.;
}
gl.uniform_4_f32_slice(
Some(
&self
.gradient
.uniforms
.locations
.color_stops,
),
&stops,
);
}
}
self.gradient.uniforms.gradient = (*gradient).clone();
}
gl.draw_elements_base_vertex(
glow::TRIANGLES,
indices.len() as i32,
glow::UNSIGNED_INT,
(last_index * std::mem::size_of::<u32>()) as i32,
last_gradient_vertex as i32,
);
last_gradient_vertex += buffers.vertices.len();
},
}
last_index += indices.len();
}
unsafe {
@ -170,47 +274,8 @@ impl Pipeline {
}
}
/// A simple shader program. Uses [`triangle.vert`] for its vertex shader and only binds position
/// attribute location.
pub(super) fn program(
gl: &glow::Context,
shader_version: &program::Version,
fragment_shader: &'static str,
) -> <glow::Context as HasContext>::Program {
unsafe {
let vertex_shader = program::Shader::vertex(
gl,
shader_version,
include_str!("shader/common/triangle.vert"),
);
let fragment_shader =
program::Shader::fragment(gl, shader_version, fragment_shader);
program::create(
gl,
&[vertex_shader, fragment_shader],
&[(0, "i_Position")],
)
}
}
pub fn set_transform(
gl: &glow::Context,
location: <glow::Context as HasContext>::UniformLocation,
transform: Transformation,
) {
unsafe {
gl.uniform_matrix_4_f32_slice(
Some(&location),
false,
transform.as_ref(),
);
}
}
#[derive(Debug)]
struct Buffer<T> {
pub struct Buffer<T> {
raw: <glow::Context as HasContext>::Buffer,
target: u32,
usage: u32,
@ -254,3 +319,268 @@ impl<T> Buffer<T> {
}
}
}
mod solid {
use crate::program;
use crate::triangle;
use glow::{Context, HasContext, NativeProgram};
use iced_graphics::triangle::ColoredVertex2D;
use iced_graphics::Transformation;
#[derive(Debug)]
pub struct Program {
pub program: <Context as HasContext>::Program,
pub vertex_array: <glow::Context as HasContext>::VertexArray,
pub vertices: triangle::Buffer<ColoredVertex2D>,
pub uniforms: Uniforms,
}
impl Program {
pub fn new(gl: &Context, shader_version: &program::Version) -> Self {
let program = unsafe {
let vertex_shader = program::Shader::vertex(
gl,
shader_version,
include_str!("shader/common/solid.vert"),
);
let fragment_shader = program::Shader::fragment(
gl,
shader_version,
include_str!("shader/common/solid.frag"),
);
program::create(
gl,
&[vertex_shader, fragment_shader],
&[(0, "i_Position"), (1, "i_Color")],
)
};
let vertex_array = unsafe {
gl.create_vertex_array().expect("Create vertex array")
};
let vertices = unsafe {
triangle::Buffer::new(
gl,
glow::ARRAY_BUFFER,
glow::DYNAMIC_DRAW,
1000,
)
};
unsafe {
gl.bind_vertex_array(Some(vertex_array));
let stride = std::mem::size_of::<ColoredVertex2D>() as i32;
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);
};
Self {
program,
vertex_array,
vertices,
uniforms: Uniforms::new(gl, program),
}
}
}
#[derive(Debug)]
pub struct Uniforms {
pub transform: Transformation,
pub transform_location: <Context as HasContext>::UniformLocation,
}
impl Uniforms {
fn new(gl: &Context, program: NativeProgram) -> Self {
let transform = Transformation::identity();
let transform_location =
unsafe { gl.get_uniform_location(program, "u_Transform") }
.expect("Solid - Get u_Transform.");
unsafe {
gl.use_program(Some(program));
gl.uniform_matrix_4_f32_slice(
Some(&transform_location),
false,
transform.as_ref(),
);
gl.use_program(None);
}
Self {
transform,
transform_location,
}
}
}
}
mod gradient {
use crate::program;
use crate::triangle;
use glow::{Context, HasContext, NativeProgram};
use iced_graphics::gradient::{self, Gradient};
use iced_graphics::triangle::Vertex2D;
use iced_graphics::Transformation;
#[derive(Debug)]
pub struct Program {
pub program: <Context as HasContext>::Program,
pub vertex_array: <glow::Context as HasContext>::VertexArray,
pub vertices: triangle::Buffer<Vertex2D>,
pub uniforms: Uniforms,
}
impl Program {
pub fn new(gl: &Context, shader_version: &program::Version) -> Self {
let program = unsafe {
let vertex_shader = program::Shader::vertex(
gl,
shader_version,
include_str!("shader/common/gradient.vert"),
);
let fragment_shader = program::Shader::fragment(
gl,
shader_version,
include_str!("shader/common/gradient.frag"),
);
program::create(
gl,
&[vertex_shader, fragment_shader],
&[(0, "i_Position")],
)
};
let vertex_array = unsafe {
gl.create_vertex_array().expect("Create vertex array")
};
let vertices = unsafe {
triangle::Buffer::new(
gl,
glow::ARRAY_BUFFER,
glow::DYNAMIC_DRAW,
1000,
)
};
unsafe {
gl.bind_vertex_array(Some(vertex_array));
let stride = std::mem::size_of::<Vertex2D>() as i32;
gl.enable_vertex_attrib_array(0);
gl.vertex_attrib_pointer_f32(
0,
2,
glow::FLOAT,
false,
stride,
0,
);
gl.bind_vertex_array(None);
};
Self {
program,
vertex_array,
vertices,
uniforms: Uniforms::new(gl, program),
}
}
}
#[derive(Debug)]
pub struct Uniforms {
pub gradient: Gradient,
pub transform: Transformation,
pub locations: Locations,
}
#[derive(Debug)]
pub struct Locations {
pub gradient_direction: <Context as HasContext>::UniformLocation,
pub color_stops_size: <Context as HasContext>::UniformLocation,
//currently the maximum number of stops is 16 due to lack of SSBO in GL2.1
pub color_stops: <Context as HasContext>::UniformLocation,
pub transform: <Context as HasContext>::UniformLocation,
}
impl Uniforms {
fn new(gl: &Context, program: NativeProgram) -> Self {
let gradient_direction = unsafe {
gl.get_uniform_location(program, "gradient_direction")
}
.expect("Gradient - Get gradient_direction.");
let color_stops_size =
unsafe { gl.get_uniform_location(program, "color_stops_size") }
.expect("Gradient - Get color_stops_size.");
let color_stops = unsafe {
gl.get_uniform_location(program, "color_stops")
.expect("Gradient - Get color_stops.")
};
let transform = Transformation::identity();
let transform_location =
unsafe { gl.get_uniform_location(program, "u_Transform") }
.expect("Solid - Get u_Transform.");
unsafe {
gl.use_program(Some(program));
gl.uniform_matrix_4_f32_slice(
Some(&transform_location),
false,
transform.as_ref(),
);
gl.use_program(None);
}
Self {
gradient: Gradient::Linear(gradient::Linear {
start: Default::default(),
end: Default::default(),
color_stops: vec![],
}),
transform: Transformation::identity(),
locations: Locations {
gradient_direction,
color_stops_size,
color_stops,
transform: transform_location,
},
}
}
}
}

View file

@ -1,162 +0,0 @@
use crate::program::Version;
use crate::triangle;
use glow::{Context, HasContext, NativeProgram};
use iced_graphics::gradient::Gradient;
use iced_graphics::gradient::Linear;
use iced_graphics::Transformation;
#[derive(Debug)]
pub struct Program {
pub program: <Context as HasContext>::Program,
pub uniform_data: UniformData,
}
#[derive(Debug)]
pub struct UniformData {
gradient: Gradient,
transform: Transformation,
uniform_locations: UniformLocations,
}
#[derive(Debug)]
struct UniformLocations {
gradient_direction_location: <Context as HasContext>::UniformLocation,
color_stops_size_location: <Context as HasContext>::UniformLocation,
//currently the maximum number of stops is 16 due to lack of SSBO in GL2.1
color_stops_location: <Context as HasContext>::UniformLocation,
transform_location: <Context as HasContext>::UniformLocation,
}
impl Program {
pub fn new(gl: &Context, shader_version: &Version) -> Self {
let program = triangle::program(
gl,
shader_version,
include_str!("../shader/common/gradient.frag"),
);
Self {
program,
uniform_data: UniformData::new(gl, program),
}
}
pub fn write_uniforms(
&mut self,
gl: &Context,
gradient: &Gradient,
transform: &Transformation,
) {
if transform != &self.uniform_data.transform {
triangle::set_transform(
gl,
self.uniform_data.uniform_locations.transform_location,
*transform,
);
}
if &self.uniform_data.gradient != gradient {
match gradient {
Gradient::Linear(linear) => unsafe {
gl.uniform_4_f32(
Some(
&self
.uniform_data
.uniform_locations
.gradient_direction_location,
),
linear.start.x,
linear.start.y,
linear.end.x,
linear.end.y,
);
gl.uniform_1_i32(
Some(
&self
.uniform_data
.uniform_locations
.color_stops_size_location,
),
(linear.color_stops.len() * 2) as i32,
);
let mut stops = [0.0; 128];
for (index, stop) in
linear.color_stops.iter().enumerate().take(16)
{
let [r, g, b, a] = stop.color.into_linear();
stops[index * 8] = r;
stops[(index * 8) + 1] = g;
stops[(index * 8) + 2] = b;
stops[(index * 8) + 3] = a;
stops[(index * 8) + 4] = stop.offset;
stops[(index * 8) + 5] = 0.;
stops[(index * 8) + 6] = 0.;
stops[(index * 8) + 7] = 0.;
}
gl.uniform_4_f32_slice(
Some(
&self
.uniform_data
.uniform_locations
.color_stops_location,
),
&stops,
);
},
}
self.uniform_data.gradient = gradient.clone();
}
}
pub fn use_program(
&mut self,
gl: &Context,
gradient: &Gradient,
transform: &Transformation,
) {
unsafe { gl.use_program(Some(self.program)) }
self.write_uniforms(gl, gradient, transform);
}
}
impl UniformData {
fn new(gl: &Context, program: NativeProgram) -> Self {
let gradient_direction_location =
unsafe { gl.get_uniform_location(program, "gradient_direction") }
.expect("Gradient - Get gradient_direction.");
let color_stops_size_location =
unsafe { gl.get_uniform_location(program, "color_stops_size") }
.expect("Gradient - Get color_stops_size.");
let color_stops_location = unsafe {
gl.get_uniform_location(program, "color_stops")
.expect("Gradient - Get color_stops.")
};
let transform_location =
unsafe { gl.get_uniform_location(program, "u_Transform") }
.expect("Gradient - Get u_Transform.");
Self {
gradient: Gradient::Linear(Linear {
start: Default::default(),
end: Default::default(),
color_stops: vec![],
}),
transform: Transformation::identity(),
uniform_locations: UniformLocations {
gradient_direction_location,
color_stops_size_location,
color_stops_location,
transform_location,
},
}
}
}

View file

@ -1,91 +0,0 @@
use crate::program::Version;
use crate::{triangle, Color};
use glow::{Context, HasContext, NativeProgram};
use iced_graphics::Transformation;
#[derive(Debug)]
pub struct Program {
program: <Context as HasContext>::Program,
uniform_data: UniformData,
}
#[derive(Debug)]
struct UniformData {
pub color: Color,
pub color_location: <Context as HasContext>::UniformLocation,
pub transform: Transformation,
pub transform_location: <Context as HasContext>::UniformLocation,
}
impl UniformData {
fn new(gl: &Context, program: NativeProgram) -> Self {
Self {
color: Color::TRANSPARENT,
color_location: unsafe {
gl.get_uniform_location(program, "color")
}
.expect("Solid - Get color."),
transform: Transformation::identity(),
transform_location: unsafe {
gl.get_uniform_location(program, "u_Transform")
}
.expect("Solid - Get u_Transform."),
}
}
}
impl Program {
pub fn new(gl: &Context, shader_version: &Version) -> Self {
let program = triangle::program(
gl,
shader_version,
include_str!("../shader/common/triangle.frag"),
);
Self {
program,
uniform_data: UniformData::new(gl, program),
}
}
pub fn write_uniforms(
&mut self,
gl: &Context,
color: &Color,
transform: &Transformation,
) {
if transform != &self.uniform_data.transform {
triangle::set_transform(
gl,
self.uniform_data.transform_location,
*transform,
)
}
if color != &self.uniform_data.color {
let [r, g, b, a] = color.into_linear();
unsafe {
gl.uniform_4_f32(
Some(&self.uniform_data.color_location),
r,
g,
b,
a,
);
}
self.uniform_data.color = *color;
}
}
pub fn use_program(
&mut self,
gl: &Context,
color: &Color,
transform: &Transformation,
) {
unsafe { gl.use_program(Some(self.program)) }
self.write_uniforms(gl, color, transform)
}
}