Merge branch 'master' into non-uniform-border-radius-for-quads
This commit is contained in:
commit
4029a1cdaa
147 changed files with 4828 additions and 2184 deletions
|
|
@ -1,3 +1,5 @@
|
|||
#[cfg(any(feature = "image", feature = "svg"))]
|
||||
use crate::image;
|
||||
use crate::quad;
|
||||
use crate::text;
|
||||
use crate::{program, triangle};
|
||||
|
|
@ -15,6 +17,8 @@ use iced_native::{Font, Size};
|
|||
/// [`iced`]: https://github.com/iced-rs/iced
|
||||
#[derive(Debug)]
|
||||
pub struct Backend {
|
||||
#[cfg(any(feature = "image", feature = "svg"))]
|
||||
image_pipeline: image::Pipeline,
|
||||
quad_pipeline: quad::Pipeline,
|
||||
text_pipeline: text::Pipeline,
|
||||
triangle_pipeline: triangle::Pipeline,
|
||||
|
|
@ -32,10 +36,14 @@ impl Backend {
|
|||
|
||||
let shader_version = program::Version::new(gl);
|
||||
|
||||
#[cfg(any(feature = "image", feature = "svg"))]
|
||||
let image_pipeline = image::Pipeline::new(gl, &shader_version);
|
||||
let quad_pipeline = quad::Pipeline::new(gl, &shader_version);
|
||||
let triangle_pipeline = triangle::Pipeline::new(gl, &shader_version);
|
||||
|
||||
Self {
|
||||
#[cfg(any(feature = "image", feature = "svg"))]
|
||||
image_pipeline,
|
||||
quad_pipeline,
|
||||
text_pipeline,
|
||||
triangle_pipeline,
|
||||
|
|
@ -70,6 +78,9 @@ impl Backend {
|
|||
viewport_size.height,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "image", feature = "svg"))]
|
||||
self.image_pipeline.trim_cache(gl);
|
||||
}
|
||||
|
||||
fn flush(
|
||||
|
|
@ -112,6 +123,21 @@ impl Backend {
|
|||
);
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "image", feature = "svg"))]
|
||||
if !layer.images.is_empty() {
|
||||
let scaled = transformation
|
||||
* Transformation::scale(scale_factor, scale_factor);
|
||||
|
||||
self.image_pipeline.draw(
|
||||
gl,
|
||||
target_height,
|
||||
scaled,
|
||||
scale_factor,
|
||||
&layer.images,
|
||||
bounds,
|
||||
);
|
||||
}
|
||||
|
||||
if !layer.text.is_empty() {
|
||||
for text in layer.text.iter() {
|
||||
// Target physical coordinates directly to avoid blurry text
|
||||
|
|
@ -238,8 +264,8 @@ impl backend::Text for Backend {
|
|||
|
||||
#[cfg(feature = "image")]
|
||||
impl backend::Image for Backend {
|
||||
fn dimensions(&self, _handle: &iced_native::image::Handle) -> (u32, u32) {
|
||||
(50, 50)
|
||||
fn dimensions(&self, handle: &iced_native::image::Handle) -> Size<u32> {
|
||||
self.image_pipeline.dimensions(handle)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -247,8 +273,8 @@ impl backend::Image for Backend {
|
|||
impl backend::Svg for Backend {
|
||||
fn viewport_dimensions(
|
||||
&self,
|
||||
_handle: &iced_native::svg::Handle,
|
||||
) -> (u32, u32) {
|
||||
(50, 50)
|
||||
handle: &iced_native::svg::Handle,
|
||||
) -> Size<u32> {
|
||||
self.image_pipeline.viewport_dimensions(handle)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
243
glow/src/image.rs
Normal file
243
glow/src/image.rs
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
mod storage;
|
||||
|
||||
use storage::Storage;
|
||||
|
||||
pub use iced_graphics::triangle::{Mesh2D, Vertex2D};
|
||||
|
||||
use crate::program::{self, Shader};
|
||||
use crate::Transformation;
|
||||
|
||||
#[cfg(feature = "image")]
|
||||
use iced_graphics::image::raster;
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
use iced_graphics::image::vector;
|
||||
|
||||
use iced_graphics::layer;
|
||||
use iced_graphics::Rectangle;
|
||||
use iced_graphics::Size;
|
||||
|
||||
use glow::HasContext;
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Pipeline {
|
||||
program: <glow::Context as HasContext>::Program,
|
||||
vertex_array: <glow::Context as HasContext>::VertexArray,
|
||||
vertex_buffer: <glow::Context as HasContext>::Buffer,
|
||||
transform_location: <glow::Context as HasContext>::UniformLocation,
|
||||
storage: Storage,
|
||||
#[cfg(feature = "image")]
|
||||
raster_cache: RefCell<raster::Cache<Storage>>,
|
||||
#[cfg(feature = "svg")]
|
||||
vector_cache: RefCell<vector::Cache<Storage>>,
|
||||
}
|
||||
|
||||
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/image.vert"),
|
||||
);
|
||||
let fragment_shader = Shader::fragment(
|
||||
gl,
|
||||
shader_version,
|
||||
include_str!("shader/common/image.frag"),
|
||||
);
|
||||
|
||||
program::create(
|
||||
gl,
|
||||
&[vertex_shader, fragment_shader],
|
||||
&[(0, "i_Position")],
|
||||
)
|
||||
};
|
||||
|
||||
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,
|
||||
);
|
||||
|
||||
gl.use_program(None);
|
||||
}
|
||||
|
||||
let vertex_buffer =
|
||||
unsafe { gl.create_buffer().expect("Create vertex buffer") };
|
||||
let vertex_array =
|
||||
unsafe { gl.create_vertex_array().expect("Create vertex array") };
|
||||
|
||||
unsafe {
|
||||
gl.bind_vertex_array(Some(vertex_array));
|
||||
gl.bind_buffer(glow::ARRAY_BUFFER, Some(vertex_buffer));
|
||||
|
||||
let vertices = &[0u8, 0, 1, 0, 0, 1, 1, 1];
|
||||
gl.buffer_data_size(
|
||||
glow::ARRAY_BUFFER,
|
||||
vertices.len() as i32,
|
||||
glow::STATIC_DRAW,
|
||||
);
|
||||
gl.buffer_sub_data_u8_slice(
|
||||
glow::ARRAY_BUFFER,
|
||||
0,
|
||||
bytemuck::cast_slice(vertices),
|
||||
);
|
||||
|
||||
gl.enable_vertex_attrib_array(0);
|
||||
gl.vertex_attrib_pointer_f32(
|
||||
0,
|
||||
2,
|
||||
glow::UNSIGNED_BYTE,
|
||||
false,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
|
||||
gl.bind_buffer(glow::ARRAY_BUFFER, None);
|
||||
gl.bind_vertex_array(None);
|
||||
}
|
||||
|
||||
Pipeline {
|
||||
program,
|
||||
vertex_array,
|
||||
vertex_buffer,
|
||||
transform_location,
|
||||
storage: Storage::default(),
|
||||
#[cfg(feature = "image")]
|
||||
raster_cache: RefCell::new(raster::Cache::default()),
|
||||
#[cfg(feature = "svg")]
|
||||
vector_cache: RefCell::new(vector::Cache::default()),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "image")]
|
||||
pub fn dimensions(&self, handle: &iced_native::image::Handle) -> Size<u32> {
|
||||
self.raster_cache.borrow_mut().load(handle).dimensions()
|
||||
}
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
pub fn viewport_dimensions(
|
||||
&self,
|
||||
handle: &iced_native::svg::Handle,
|
||||
) -> Size<u32> {
|
||||
let mut cache = self.vector_cache.borrow_mut();
|
||||
let svg = cache.load(handle);
|
||||
|
||||
svg.viewport_dimensions()
|
||||
}
|
||||
|
||||
pub fn draw(
|
||||
&mut self,
|
||||
mut gl: &glow::Context,
|
||||
target_height: u32,
|
||||
transformation: Transformation,
|
||||
_scale_factor: f32,
|
||||
images: &[layer::Image],
|
||||
layer_bounds: Rectangle<u32>,
|
||||
) {
|
||||
unsafe {
|
||||
gl.use_program(Some(self.program));
|
||||
gl.bind_vertex_array(Some(self.vertex_array));
|
||||
gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vertex_buffer));
|
||||
gl.enable(glow::SCISSOR_TEST);
|
||||
}
|
||||
|
||||
#[cfg(feature = "image")]
|
||||
let mut raster_cache = self.raster_cache.borrow_mut();
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
let mut vector_cache = self.vector_cache.borrow_mut();
|
||||
|
||||
for image in images {
|
||||
let (entry, bounds) = match &image {
|
||||
#[cfg(feature = "image")]
|
||||
layer::Image::Raster { handle, bounds } => (
|
||||
raster_cache.upload(handle, &mut gl, &mut self.storage),
|
||||
bounds,
|
||||
),
|
||||
#[cfg(not(feature = "image"))]
|
||||
layer::Image::Raster { handle: _, bounds } => (None, bounds),
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
layer::Image::Vector { handle, bounds } => {
|
||||
let size = [bounds.width, bounds.height];
|
||||
(
|
||||
vector_cache.upload(
|
||||
handle,
|
||||
size,
|
||||
_scale_factor,
|
||||
&mut gl,
|
||||
&mut self.storage,
|
||||
),
|
||||
bounds,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "svg"))]
|
||||
layer::Image::Vector { handle: _, bounds } => (None, bounds),
|
||||
};
|
||||
|
||||
unsafe {
|
||||
gl.scissor(
|
||||
layer_bounds.x as i32,
|
||||
(target_height - (layer_bounds.y + layer_bounds.height))
|
||||
as i32,
|
||||
layer_bounds.width as i32,
|
||||
layer_bounds.height as i32,
|
||||
);
|
||||
|
||||
if let Some(storage::Entry { texture, .. }) = entry {
|
||||
gl.bind_texture(glow::TEXTURE_2D, Some(*texture))
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
let translate = Transformation::translate(bounds.x, bounds.y);
|
||||
let scale = Transformation::scale(bounds.width, bounds.height);
|
||||
let transformation = transformation * translate * scale;
|
||||
let matrix: [f32; 16] = transformation.into();
|
||||
gl.uniform_matrix_4_f32_slice(
|
||||
Some(&self.transform_location),
|
||||
false,
|
||||
&matrix,
|
||||
);
|
||||
|
||||
gl.draw_arrays(glow::TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
gl.bind_texture(glow::TEXTURE_2D, None);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
gl.bind_buffer(glow::ARRAY_BUFFER, None);
|
||||
gl.bind_vertex_array(None);
|
||||
gl.use_program(None);
|
||||
gl.disable(glow::SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trim_cache(&mut self, mut gl: &glow::Context) {
|
||||
#[cfg(feature = "image")]
|
||||
self.raster_cache
|
||||
.borrow_mut()
|
||||
.trim(&mut self.storage, &mut gl);
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
self.vector_cache
|
||||
.borrow_mut()
|
||||
.trim(&mut self.storage, &mut gl);
|
||||
}
|
||||
}
|
||||
78
glow/src/image/storage.rs
Normal file
78
glow/src/image/storage.rs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
use iced_graphics::image;
|
||||
use iced_graphics::Size;
|
||||
|
||||
use glow::HasContext;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Storage;
|
||||
|
||||
impl image::Storage for Storage {
|
||||
type Entry = Entry;
|
||||
type State<'a> = &'a glow::Context;
|
||||
|
||||
fn upload(
|
||||
&mut self,
|
||||
width: u32,
|
||||
height: u32,
|
||||
data: &[u8],
|
||||
gl: &mut &glow::Context,
|
||||
) -> Option<Self::Entry> {
|
||||
unsafe {
|
||||
let texture = gl.create_texture().expect("create texture");
|
||||
gl.bind_texture(glow::TEXTURE_2D, Some(texture));
|
||||
gl.tex_image_2d(
|
||||
glow::TEXTURE_2D,
|
||||
0,
|
||||
glow::SRGB8_ALPHA8 as i32,
|
||||
width as i32,
|
||||
height as i32,
|
||||
0,
|
||||
glow::RGBA,
|
||||
glow::UNSIGNED_BYTE,
|
||||
Some(data),
|
||||
);
|
||||
gl.tex_parameter_i32(
|
||||
glow::TEXTURE_2D,
|
||||
glow::TEXTURE_WRAP_S,
|
||||
glow::CLAMP_TO_EDGE as _,
|
||||
);
|
||||
gl.tex_parameter_i32(
|
||||
glow::TEXTURE_2D,
|
||||
glow::TEXTURE_WRAP_T,
|
||||
glow::CLAMP_TO_EDGE as _,
|
||||
);
|
||||
gl.tex_parameter_i32(
|
||||
glow::TEXTURE_2D,
|
||||
glow::TEXTURE_MIN_FILTER,
|
||||
glow::LINEAR as _,
|
||||
);
|
||||
gl.tex_parameter_i32(
|
||||
glow::TEXTURE_2D,
|
||||
glow::TEXTURE_MAG_FILTER,
|
||||
glow::LINEAR as _,
|
||||
);
|
||||
gl.bind_texture(glow::TEXTURE_2D, None);
|
||||
|
||||
Some(Entry {
|
||||
size: Size::new(width, height),
|
||||
texture,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn remove(&mut self, entry: &Entry, gl: &mut &glow::Context) {
|
||||
unsafe { gl.delete_texture(entry.texture) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Entry {
|
||||
size: Size<u32>,
|
||||
pub(super) texture: glow::NativeTexture,
|
||||
}
|
||||
|
||||
impl image::storage::Entry for Entry {
|
||||
fn size(&self) -> Size<u32> {
|
||||
self.size
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
//! 
|
||||
//!
|
||||
//! [`glow`]: https://github.com/grovesNL/glow
|
||||
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
|
||||
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.5/native
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
|
||||
)]
|
||||
|
|
@ -24,6 +24,8 @@
|
|||
pub use glow;
|
||||
|
||||
mod backend;
|
||||
#[cfg(any(feature = "image", feature = "svg"))]
|
||||
mod image;
|
||||
mod program;
|
||||
mod quad;
|
||||
mod text;
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
#ifdef GL_ES
|
||||
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
||||
precision highp float;
|
||||
#else
|
||||
precision mediump float;
|
||||
#endif
|
||||
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
||||
precision highp float;
|
||||
#else
|
||||
precision mediump float;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HIGHER_THAN_300
|
||||
layout (location = 0) out vec4 fragColor;
|
||||
#define gl_FragColor fragColor
|
||||
layout (location = 0) out vec4 fragColor;
|
||||
#define gl_FragColor fragColor
|
||||
#endif
|
||||
|
||||
in vec2 raw_position;
|
||||
|
||||
uniform vec4 gradient_direction;
|
||||
uniform uint color_stops_size;
|
||||
uniform int color_stops_size;
|
||||
// GLSL does not support dynamically sized arrays without SSBOs so this is capped to 16 stops
|
||||
//stored as color(vec4) -> offset(vec4) sequentially;
|
||||
uniform vec4 color_stops[32];
|
||||
|
|
@ -28,23 +28,23 @@ void main() {
|
|||
vec2 unit = normalize(gradient_vec);
|
||||
float coord_offset = dot(unit, current_vec) / length(gradient_vec);
|
||||
//if a gradient has a start/end stop that is identical, the mesh will have a transparent fill
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
float min_offset = color_stops[1].x;
|
||||
float max_offset = color_stops[color_stops_size - 1u].x;
|
||||
float max_offset = color_stops[color_stops_size - 1].x;
|
||||
|
||||
for (uint i = 0u; i < color_stops_size - 2u; i += 2u) {
|
||||
float curr_offset = color_stops[i+1u].x;
|
||||
float next_offset = color_stops[i+3u].x;
|
||||
for (int i = 0; i < color_stops_size - 2; i += 2) {
|
||||
float curr_offset = color_stops[i+1].x;
|
||||
float next_offset = color_stops[i+3].x;
|
||||
|
||||
if (coord_offset <= min_offset) {
|
||||
//current coordinate is before the first defined offset, set it to the start color
|
||||
fragColor = color_stops[0];
|
||||
gl_FragColor = color_stops[0];
|
||||
}
|
||||
|
||||
if (curr_offset <= coord_offset && coord_offset <= next_offset) {
|
||||
//current fragment is between the current offset processing & the next one, interpolate colors
|
||||
fragColor = mix(color_stops[i], color_stops[i+2u], smoothstep(
|
||||
gl_FragColor = mix(color_stops[i], color_stops[i+2], smoothstep(
|
||||
curr_offset,
|
||||
next_offset,
|
||||
coord_offset
|
||||
|
|
@ -53,7 +53,7 @@ void main() {
|
|||
|
||||
if (coord_offset >= max_offset) {
|
||||
//current coordinate is before the last defined offset, set it to the last color
|
||||
fragColor = color_stops[color_stops_size - 2u];
|
||||
gl_FragColor = color_stops[color_stops_size - 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
22
glow/src/shader/common/image.frag
Normal file
22
glow/src/shader/common/image.frag
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#ifdef GL_ES
|
||||
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
||||
precision highp float;
|
||||
#else
|
||||
precision mediump float;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
uniform sampler2D tex;
|
||||
in vec2 tex_pos;
|
||||
|
||||
#ifdef HIGHER_THAN_300
|
||||
out vec4 fragColor;
|
||||
#define gl_FragColor fragColor
|
||||
#endif
|
||||
#ifdef GL_ES
|
||||
#define texture texture2D
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
gl_FragColor = texture(tex, tex_pos);
|
||||
}
|
||||
9
glow/src/shader/common/image.vert
Normal file
9
glow/src/shader/common/image.vert
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
uniform mat4 u_Transform;
|
||||
|
||||
in vec2 i_Position;
|
||||
out vec2 tex_pos;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_Transform * vec4(i_Position, 0.0, 1.0);
|
||||
tex_pos = i_Position;
|
||||
}
|
||||
|
|
@ -11,8 +11,8 @@ out vec4 fragColor;
|
|||
#define gl_FragColor fragColor
|
||||
#endif
|
||||
|
||||
uniform vec4 color;
|
||||
in vec4 v_Color;
|
||||
|
||||
void main() {
|
||||
fragColor = color;
|
||||
gl_FragColor = v_Color;
|
||||
}
|
||||
11
glow/src/shader/common/solid.vert
Normal file
11
glow/src/shader/common/solid.vert
Normal 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;
|
||||
}
|
||||
|
|
@ -1,74 +1,52 @@
|
|||
//! 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,
|
||||
}
|
||||
const DEFAULT_VERTICES: usize = 1_000;
|
||||
const DEFAULT_INDICES: usize = 1_000;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ProgramList {
|
||||
pub(crate) struct Pipeline {
|
||||
indices: Buffer<u32>,
|
||||
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,
|
||||
DEFAULT_INDICES,
|
||||
)
|
||||
};
|
||||
|
||||
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 +61,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,29 +147,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);
|
||||
}
|
||||
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 {
|
||||
|
|
@ -169,47 +277,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,
|
||||
|
|
@ -253,3 +322,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,
|
||||
super::DEFAULT_VERTICES,
|
||||
)
|
||||
};
|
||||
|
||||
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,
|
||||
super::DEFAULT_VERTICES,
|
||||
)
|
||||
};
|
||||
|
||||
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,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_u32(
|
||||
Some(
|
||||
&self
|
||||
.uniform_data
|
||||
.uniform_locations
|
||||
.color_stops_size_location,
|
||||
),
|
||||
(linear.color_stops.len() * 2) as u32,
|
||||
);
|
||||
|
||||
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,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue