Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

non uniform border radius for quads #1506

Merged
merged 8 commits into from
Dec 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions examples/custom_quad/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "custom_quad"
version = "0.1.0"
authors = ["Robert Krahn"]
edition = "2021"
publish = false

[dependencies]
iced = { path = "../.." }
iced_native = { path = "../../native" }
160 changes: 160 additions & 0 deletions examples/custom_quad/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
//! This example showcases a drawing a quad.
mod quad {
use iced_native::layout::{self, Layout};
use iced_native::renderer;
use iced_native::widget::{self, Widget};
use iced_native::{Color, Element, Length, Point, Rectangle, Size};

pub struct CustomQuad {
size: f32,
radius: [f32; 4],
border_width: f32,
}

impl CustomQuad {
pub fn new(size: f32, radius: [f32; 4], border_width: f32) -> Self {
Self {
size,
radius,
border_width,
}
}
}

impl<Message, Renderer> Widget<Message, Renderer> for CustomQuad
where
Renderer: renderer::Renderer,
{
fn width(&self) -> Length {
Length::Shrink
}

fn height(&self) -> Length {
Length::Shrink
}

fn layout(
&self,
_renderer: &Renderer,
_limits: &layout::Limits,
) -> layout::Node {
layout::Node::new(Size::new(self.size, self.size))
}

fn draw(
&self,
_state: &widget::Tree,
renderer: &mut Renderer,
_theme: &Renderer::Theme,
_style: &renderer::Style,
layout: Layout<'_>,
_cursor_position: Point,
_viewport: &Rectangle,
) {
renderer.fill_quad(
renderer::Quad {
bounds: layout.bounds(),
border_radius: self.radius.into(),
border_width: self.border_width,
border_color: Color::from_rgb(1.0, 0.0, 0.0),
},
Color::BLACK,
);
}
}

impl<'a, Message, Renderer> From<CustomQuad> for Element<'a, Message, Renderer>
where
Renderer: renderer::Renderer,
{
fn from(circle: CustomQuad) -> Self {
Self::new(circle)
}
}
}

use iced::widget::{column, container, slider, text};
use iced::{Alignment, Element, Length, Sandbox, Settings};

pub fn main() -> iced::Result {
Example::run(Settings::default())
}

struct Example {
radius: [f32; 4],
border_width: f32,
}

#[derive(Debug, Clone, Copy)]
#[allow(clippy::enum_variant_names)]
enum Message {
RadiusTopLeftChanged(f32),
RadiusTopRightChanged(f32),
RadiusBottomRightChanged(f32),
RadiusBottomLeftChanged(f32),
BorderWidthChanged(f32),
}

impl Sandbox for Example {
type Message = Message;

fn new() -> Self {
Self {
radius: [50.0; 4],
border_width: 0.0,
}
}

fn title(&self) -> String {
String::from("Custom widget - Iced")
}

fn update(&mut self, message: Message) {
let [tl, tr, br, bl] = self.radius;
match message {
Message::RadiusTopLeftChanged(radius) => {
self.radius = [radius, tr, br, bl];
}
Message::RadiusTopRightChanged(radius) => {
self.radius = [tl, radius, br, bl];
}
Message::RadiusBottomRightChanged(radius) => {
self.radius = [tl, tr, radius, bl];
}
Message::RadiusBottomLeftChanged(radius) => {
self.radius = [tl, tr, br, radius];
}
Message::BorderWidthChanged(width) => {
self.border_width = width;
}
}
}

fn view(&self) -> Element<Message> {
let [tl, tr, br, bl] = self.radius;

let content = column![
quad::CustomQuad::new(200.0, self.radius, self.border_width),
text(format!("Radius: {tl:.2}/{tr:.2}/{br:.2}/{bl:.2}")),
slider(1.0..=100.0, tl, Message::RadiusTopLeftChanged).step(0.01),
slider(1.0..=100.0, tr, Message::RadiusTopRightChanged).step(0.01),
slider(1.0..=100.0, br, Message::RadiusBottomRightChanged)
.step(0.01),
slider(1.0..=100.0, bl, Message::RadiusBottomLeftChanged)
.step(0.01),
slider(1.0..=10.0, self.border_width, Message::BorderWidthChanged)
.step(0.01),
]
.padding(20)
.spacing(20)
.max_width(500)
.align_items(Alignment::Center);

container(content)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.into()
}
}
2 changes: 1 addition & 1 deletion examples/custom_widget/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ mod circle {
renderer.fill_quad(
renderer::Quad {
bounds: layout.bounds(),
border_radius: self.radius,
border_radius: self.radius.into(),
border_width: 0.0,
border_color: Color::TRANSPARENT,
},
Expand Down
2 changes: 1 addition & 1 deletion examples/modal/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ mod modal {
renderer.fill_quad(
renderer::Quad {
bounds: layout.bounds(),
border_radius: 0.0,
border_radius: renderer::BorderRadius::from(0.0),
border_width: 0.0,
border_color: Color::TRANSPARENT,
},
Expand Down
8 changes: 4 additions & 4 deletions glow/src/quad/compatibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ unsafe fn create_buffers(
gl.enable_vertex_attrib_array(4);
gl.vertex_attrib_pointer_f32(
4,
1,
4,
glow::FLOAT,
false,
stride,
Expand All @@ -268,7 +268,7 @@ unsafe fn create_buffers(
glow::FLOAT,
false,
stride,
4 * (2 + 2 + 4 + 4 + 1),
4 * (2 + 2 + 4 + 4 + 4),
);

gl.enable_vertex_attrib_array(6);
Expand All @@ -278,7 +278,7 @@ unsafe fn create_buffers(
glow::FLOAT,
false,
stride,
4 * (2 + 2 + 4 + 4 + 1 + 1),
4 * (2 + 2 + 4 + 4 + 4 + 1),
);

gl.bind_vertex_array(None);
Expand Down Expand Up @@ -307,7 +307,7 @@ pub struct Vertex {
pub border_color: [f32; 4],

/// The border radius of the [`Vertex`].
pub border_radius: f32,
pub border_radius: [f32; 4],

/// The border width of the [`Vertex`].
pub border_width: f32,
Expand Down
4 changes: 2 additions & 2 deletions glow/src/quad/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ unsafe fn create_instance_buffer(
gl.enable_vertex_attrib_array(4);
gl.vertex_attrib_pointer_f32(
4,
1,
4,
glow::FLOAT,
false,
stride,
Expand All @@ -233,7 +233,7 @@ unsafe fn create_instance_buffer(
glow::FLOAT,
false,
stride,
4 * (2 + 2 + 4 + 4 + 1),
4 * (2 + 2 + 4 + 4 + 4),
);
gl.vertex_attrib_divisor(5, 1);

Expand Down
24 changes: 20 additions & 4 deletions glow/src/shader/compatibility/quad.frag
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ varying vec4 v_Color;
varying vec4 v_BorderColor;
varying vec2 v_Pos;
varying vec2 v_Scale;
varying float v_BorderRadius;
varying vec4 v_BorderRadius;
varying float v_BorderWidth;

float _distance(vec2 frag_coord, vec2 position, vec2 size, float radius)
Expand All @@ -33,10 +33,26 @@ float _distance(vec2 frag_coord, vec2 position, vec2 size, float radius)
return sqrt(distance.x * distance.x + distance.y * distance.y);
}

float selectBorderRadius(vec4 radi, vec2 position, vec2 center)
{
float rx = radi.x;
float ry = radi.y;
rx = position.x > center.x ? radi.y : radi.x;
ry = position.x > center.x ? radi.z : radi.w;
rx = position.y > center.y ? ry : rx;
return rx;
}

void main() {
vec2 fragCoord = vec2(gl_FragCoord.x, u_ScreenHeight - gl_FragCoord.y);

float internal_border = max(v_BorderRadius - v_BorderWidth, 0.0);
float border_radius = selectBorderRadius(
v_BorderRadius,
fragCoord,
(v_Pos + v_Scale * 0.5).xy
);

float internal_border = max(border_radius - v_BorderWidth, 0.0);

float internal_distance = _distance(
fragCoord,
Expand All @@ -57,11 +73,11 @@ void main() {
fragCoord,
v_Pos,
v_Scale,
v_BorderRadius
border_radius
);

float radius_alpha =
1.0 - smoothstep(max(v_BorderRadius - 0.5, 0.0), v_BorderRadius + 0.5, d);
1.0 - smoothstep(max(border_radius - 0.5, 0.0), border_radius + 0.5, d);

gl_FragColor = vec4(mixed_color.xyz, mixed_color.w * radius_alpha);
}
12 changes: 7 additions & 5 deletions glow/src/shader/compatibility/quad.vert
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,27 @@ attribute vec2 i_Pos;
attribute vec2 i_Scale;
attribute vec4 i_Color;
attribute vec4 i_BorderColor;
attribute float i_BorderRadius;
attribute vec4 i_BorderRadius;
attribute float i_BorderWidth;
attribute vec2 q_Pos;

varying vec4 v_Color;
varying vec4 v_BorderColor;
varying vec2 v_Pos;
varying vec2 v_Scale;
varying float v_BorderRadius;
varying vec4 v_BorderRadius;
varying float v_BorderWidth;


void main() {
vec2 p_Pos = i_Pos * u_Scale;
vec2 p_Scale = i_Scale * u_Scale;

float i_BorderRadius = min(
i_BorderRadius,
min(i_Scale.x, i_Scale.y) / 2.0
vec4 i_BorderRadius = vec4(
min(i_BorderRadius.x, min(i_Scale.x, i_Scale.y) / 2.0),
min(i_BorderRadius.y, min(i_Scale.x, i_Scale.y) / 2.0),
min(i_BorderRadius.z, min(i_Scale.x, i_Scale.y) / 2.0),
min(i_BorderRadius.w, min(i_Scale.x, i_Scale.y) / 2.0)
);

mat4 i_Transform = mat4(
Expand Down
24 changes: 20 additions & 4 deletions glow/src/shader/core/quad.frag
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ in vec4 v_Color;
in vec4 v_BorderColor;
in vec2 v_Pos;
in vec2 v_Scale;
in float v_BorderRadius;
in vec4 v_BorderRadius;
in float v_BorderWidth;

float fDistance(vec2 frag_coord, vec2 position, vec2 size, float radius)
Expand All @@ -38,14 +38,30 @@ float fDistance(vec2 frag_coord, vec2 position, vec2 size, float radius)
return sqrt(distance.x * distance.x + distance.y * distance.y);
}

float selectBorderRadius(vec4 radi, vec2 position, vec2 center)
{
float rx = radi.x;
float ry = radi.y;
rx = position.x > center.x ? radi.y : radi.x;
ry = position.x > center.x ? radi.z : radi.w;
rx = position.y > center.y ? ry : rx;
return rx;
}

void main() {
vec4 mixed_color;

vec2 fragCoord = vec2(gl_FragCoord.x, u_ScreenHeight - gl_FragCoord.y);

float border_radius = selectBorderRadius(
v_BorderRadius,
fragCoord,
(v_Pos + v_Scale * 0.5).xy
);

// TODO: Remove branching (?)
if(v_BorderWidth > 0.0) {
float internal_border = max(v_BorderRadius - v_BorderWidth, 0.0);
float internal_border = max(border_radius - v_BorderWidth, 0.0);

float internal_distance = fDistance(
fragCoord,
Expand All @@ -69,11 +85,11 @@ void main() {
fragCoord,
v_Pos,
v_Scale,
v_BorderRadius
border_radius
);

float radius_alpha =
1.0 - smoothstep(max(v_BorderRadius - 0.5, 0.0), v_BorderRadius + 0.5, d);
1.0 - smoothstep(max(border_radius - 0.5, 0.0), border_radius + 0.5, d);

gl_FragColor = vec4(mixed_color.xyz, mixed_color.w * radius_alpha);
}
Loading