Skip to content

Feathers color widgets #19984

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

Draft
wants to merge 19 commits into
base: main
Choose a base branch
from
Draft
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
2 changes: 2 additions & 0 deletions crates/bevy_feathers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ bevy_log = { path = "../bevy_log", version = "0.17.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.17.0-dev" }
bevy_picking = { path = "../bevy_picking", version = "0.17.0-dev" }
bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev" }
bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev" }
bevy_render = { path = "../bevy_render", version = "0.17.0-dev" }
bevy_text = { path = "../bevy_text", version = "0.17.0-dev" }
bevy_ui = { path = "../bevy_ui", version = "0.17.0-dev", features = [
"bevy_ui_picking_backend",
] }
bevy_ui_render = { path = "../bevy_ui_render", version = "0.17.0-dev" }
bevy_window = { path = "../bevy_window", version = "0.17.0-dev" }
bevy_winit = { path = "../bevy_winit", version = "0.17.0-dev" }

Expand Down
59 changes: 59 additions & 0 deletions crates/bevy_feathers/src/alpha_pattern.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use bevy_app::Plugin;
use bevy_asset::{Asset, Assets, Handle};
use bevy_ecs::{
component::Component,
lifecycle::Add,
observer::On,
resource::Resource,
system::{Query, Res},
world::FromWorld,
};
use bevy_reflect::TypePath;
use bevy_render::render_resource::{AsBindGroup, ShaderRef};
use bevy_ui_render::ui_material::{MaterialNode, UiMaterial};

#[derive(AsBindGroup, Asset, TypePath, Default, Debug, Clone)]
pub(crate) struct AlphaPatternMaterial {}

impl UiMaterial for AlphaPatternMaterial {
fn fragment_shader() -> ShaderRef {
"embedded://bevy_feathers/assets/shaders/alpha_pattern.wgsl".into()
}
}

#[derive(Resource)]
pub(crate) struct AlphaPatternResource(pub(crate) Handle<AlphaPatternMaterial>);

impl FromWorld for AlphaPatternResource {
fn from_world(world: &mut bevy_ecs::world::World) -> Self {
let mut ui_materials = world
.get_resource_mut::<Assets<AlphaPatternMaterial>>()
.unwrap();
Self(ui_materials.add(AlphaPatternMaterial::default()))
}
}

/// Marker that tells us we want to fill in the [`MaterialNode`] with the alpha material.
#[derive(Component, Default, Clone)]
pub(crate) struct AlphaPattern;

/// Observer to fill in the material handle (since we don't have access to the materials asset
/// in the template)
fn on_add_color_swatch(
ev: On<Add, AlphaPattern>,
mut q_swatch: Query<&mut MaterialNode<AlphaPatternMaterial>>,
r_material: Res<AlphaPatternResource>,
) {
if let Ok(mut material) = q_swatch.get_mut(ev.target()) {
material.0 = r_material.0.clone();
}
}

/// Plugin which registers the systems for updating the button styles.
pub struct AlphaPatternPlugin;

impl Plugin for AlphaPatternPlugin {
fn build(&self, app: &mut bevy_app::App) {
app.add_observer(on_add_color_swatch);
}
}
39 changes: 39 additions & 0 deletions crates/bevy_feathers/src/assets/shaders/alpha_pattern.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// This shader draws a checkerboard pattern
#import bevy_ui::ui_vertex_output::UiVertexOutput

@fragment
fn fragment(in: UiVertexOutput) -> @location(0) vec4<f32> {
let uv = (in.uv - vec2<f32>(0.5, 0.5)) * in.size / 16.;
let check = select(0.0, 1.0, (fract(uv.x) < 0.5) != (fract(uv.y) < 0.5));
let bg = mix(vec3<f32>(0.2, 0.2, 0.2), vec3<f32>(0.6, 0.6, 0.6), check);

let size = vec2<f32>(in.size.x, in.size.y);
let external_distance = sd_rounded_box((in.uv - 0.5) * size, size, in.border_radius);
let alpha = smoothstep(0.5, -0.5, external_distance);

return vec4<f32>(bg, alpha);
}

// From: https://github.com/bevyengine/bevy/pull/8973
// The returned value is the shortest distance from the given point to the boundary of the rounded box.
// Negative values indicate that the point is inside the rounded box, positive values that the point is outside, and zero is exactly on the boundary.
// arguments
// point -> The function will return the distance from this point to the closest point on the boundary.
// size -> The maximum width and height of the box.
// corner_radii -> The radius of each rounded corner. Ordered counter clockwise starting top left:
// x = top left, y = top right, z = bottom right, w = bottom left.
fn sd_rounded_box(point: vec2<f32>, size: vec2<f32>, corner_radii: vec4<f32>) -> f32 {
// if 0.0 < y then select bottom left (w) and bottom right corner radius (z)
// else select top left (x) and top right corner radius (y)
let rs = select(corner_radii.xy, corner_radii.wz, 0.0 < point.y);
// w and z are swapped so that both pairs are in left to right order, otherwise this second select statement would return the incorrect value for the bottom pair.
let radius = select(rs.x, rs.y, 0.0 < point.x);
// Vector from the corner closest to the point, to the point
let corner_to_point = abs(point) - 0.5 * size;
// Vector from the center of the radius circle to the point
let q = corner_to_point + radius;
// length from center of the radius circle to the point, 0s a component if the point is not within the quadrant of the radius circle that is part of the curved corner.
let l = length(max(q, vec2(0.0)));
let m = min(max(q.x, q.y), 0.0);
return l + m - radius;
}
Loading