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

Added ability to define colors at UV coordinates along a path #4353

Merged
merged 29 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
912ced2
added ability to add custom gradients to paths
murl-digital Apr 12, 2024
18c561d
add docs
murl-digital Apr 12, 2024
4279851
re-add send sync assertion
murl-digital Apr 12, 2024
fe92ba8
better documentation
murl-digital Apr 13, 2024
c433de3
fix typo in docs
murl-digital Apr 13, 2024
e03fe52
added rect bounds for uv mapping
murl-digital Apr 13, 2024
c9efc24
added benchmarks for colors
murl-digital Apr 16, 2024
6664482
simplify ColorMode and use a better method for calculating bounding b…
murl-digital Apr 16, 2024
5451e30
fix feathering oversight
murl-digital Apr 16, 2024
41f8192
refactor ColorMode out into its own file
murl-digital Apr 16, 2024
2d8ab0c
add transparent helper
murl-digital Apr 16, 2024
a8e0e57
add proper stroke color demo
murl-digital Apr 16, 2024
f8e6b65
actually use the ColorMode::TRANSPARENT
murl-digital Apr 16, 2024
b6c4ce2
expand the bounding box to include the thickness of the path
murl-digital Apr 16, 2024
46cd485
add a few more benchmarks
murl-digital Apr 16, 2024
713f566
add a unit test to check if all points are within the given bounding …
murl-digital Apr 17, 2024
4884aad
have UV color modes be affected by tints
murl-digital Apr 20, 2024
5f40909
Merge branch 'emilk:master' into feature/uv-line
murl-digital Apr 21, 2024
f71b011
remove dependencies for dancing strings demo (doesn't compile for me …
murl-digital Apr 21, 2024
1e85d86
roll dancing strings examples into one
murl-digital Apr 21, 2024
eb41420
Merge branch 'emilk:master' into feature/uv-line
murl-digital Apr 21, 2024
cdc6588
from_hex! can't be used in statics
murl-digital Apr 21, 2024
38bc770
remove margin, it seems that points can exit the rect by at most 0.55…
murl-digital Apr 21, 2024
b1f7520
remove unesecarry box for closure
murl-digital Apr 21, 2024
2283268
add benchmarks for uv mode lines
murl-digital Apr 21, 2024
5f3a712
why are you still here, mx. box?
murl-digital Apr 22, 2024
1a95c48
fix docs
murl-digital Apr 22, 2024
52a6459
remove mul_color
murl-digital Apr 22, 2024
a92ed91
Simplify the dancing strings example
emilk Apr 22, 2024
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
83 changes: 83 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 8 additions & 8 deletions crates/egui/src/painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
};
use epaint::{
text::{Fonts, Galley, LayoutJob},
CircleShape, ClippedShape, RectShape, Rounding, Shape, Stroke,
CircleShape, ClippedShape, PathStroke, RectShape, Rounding, Shape, Stroke,
};

/// Helper to paint shapes and text to a specific region on a specific layer.
Expand Down Expand Up @@ -280,21 +280,21 @@ impl Painter {
/// # Paint different primitives
impl Painter {
/// Paints a line from the first point to the second.
pub fn line_segment(&self, points: [Pos2; 2], stroke: impl Into<Stroke>) -> ShapeIdx {
pub fn line_segment(&self, points: [Pos2; 2], stroke: impl Into<PathStroke>) -> ShapeIdx {
self.add(Shape::LineSegment {
points,
stroke: stroke.into(),
})
}

/// Paints a horizontal line.
pub fn hline(&self, x: impl Into<Rangef>, y: f32, stroke: impl Into<Stroke>) -> ShapeIdx {
self.add(Shape::hline(x, y, stroke))
pub fn hline(&self, x: impl Into<Rangef>, y: f32, stroke: impl Into<PathStroke>) -> ShapeIdx {
self.add(Shape::hline(x, y, stroke.into()))
}

/// Paints a vertical line.
pub fn vline(&self, x: f32, y: impl Into<Rangef>, stroke: impl Into<Stroke>) -> ShapeIdx {
self.add(Shape::vline(x, y, stroke))
pub fn vline(&self, x: f32, y: impl Into<Rangef>, stroke: impl Into<PathStroke>) -> ShapeIdx {
self.add(Shape::vline(x, y, stroke.into()))
}

pub fn circle(
Expand Down Expand Up @@ -513,15 +513,15 @@ impl Painter {
}

fn tint_shape_towards(shape: &mut Shape, target: Color32) {
epaint::shape_transform::adjust_colors(shape, &|color| {
epaint::shape_transform::adjust_colors(shape, move |color| {
if *color != Color32::PLACEHOLDER {
*color = crate::ecolor::tint_color_towards(*color, target);
}
});
}

fn multiply_opacity(shape: &mut Shape, opacity: f32) {
epaint::shape_transform::adjust_colors(shape, &|color| {
epaint::shape_transform::adjust_colors(shape, move |color| {
if *color != Color32::PLACEHOLDER {
*color = color.gamma_multiply(opacity);
}
Expand Down
3 changes: 3 additions & 0 deletions crates/egui_demo_lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ chrono = { version = "0.4", optional = true, features = ["js-sys", "wasmbind"] }
## Enable this when generating docs.
document-features = { workspace = true, optional = true }
serde = { version = "1", optional = true, features = ["derive"] }
once_cell = "1.19"
colorgrad = "0.6"
noise = "0.9"
emilk marked this conversation as resolved.
Show resolved Hide resolved


[dev-dependencies]
Expand Down
90 changes: 90 additions & 0 deletions crates/egui_demo_lib/src/demo/dancing_trans_strings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use colorgrad::{Color, CustomGradient, Gradient};
use egui::{containers::*, epaint::PathStroke, *};
use noise::{NoiseFn, OpenSimplex};
use once_cell::sync::Lazy;

static GRADIENT: Lazy<Gradient> = Lazy::new(|| {
CustomGradient::new()
.colors(&[
Color::from_html("#5BCEFA").unwrap(),
Color::from_html("#F5A9B8").unwrap(),
Color::from_html("#FFFFFF").unwrap(),
Color::from_html("#F5A9B8").unwrap(),
Color::from_html("#5BCEFA").unwrap(),
])
.build()
.unwrap_or(colorgrad::rainbow())
});
static NOISE: Lazy<OpenSimplex> = Lazy::new(|| OpenSimplex::new(6940));

#[derive(Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct DancingStrings {}

impl super::Demo for DancingStrings {
fn name(&self) -> &'static str {
"♫ Dancing Strings (Colored)"
}

fn show(&mut self, ctx: &Context, open: &mut bool) {
use super::View as _;
Window::new(self.name())
.open(open)
.default_size(vec2(512.0, 256.0))
.vscroll(false)
.show(ctx, |ui| self.ui(ui));
}
}

impl super::View for DancingStrings {
fn ui(&mut self, ui: &mut Ui) {
Frame::canvas(ui.style()).show(ui, |ui| {
ui.ctx().request_repaint();
let time = ui.input(|i| i.time);

let desired_size = ui.available_width() * vec2(1.0, 0.35);
let (_id, rect) = ui.allocate_space(desired_size);

let to_screen =
emath::RectTransform::from_to(Rect::from_x_y_ranges(0.0..=1.0, -1.0..=1.0), rect);

let mut shapes = vec![];

for &mode in &[2, 3, 5] {
let mode = mode as f64;
let n = 120;
let speed = 1.5;

let points: Vec<Pos2> = (0..=n)
.map(|i| {
let t = i as f64 / (n as f64);
let amp = (time * speed * mode).sin() / mode;
let y = amp * (t * std::f64::consts::TAU / 2.0 * mode).sin();
to_screen * pos2(t as f32, y as f32)
})
.collect();

let thickness = 10.0 / mode as f32;
shapes.push(epaint::Shape::line(
points,
PathStroke::new_uv(thickness, move |_r, p| {
let time = time / 10.0;
let x = remap(p.x, rect.x_range(), 0.0..=1.0) as f64;
let y = remap(p.y, rect.y_range(), 0.0..=1.0) as f64;

let noise = NOISE.get([x * 1.25 + time, y * 1.25 + time]);
let color = GRADIENT.at(noise).to_rgba8();

Color32::from_rgba_premultiplied(color[0], color[1], color[2], color[3])
}),
));
}

ui.painter().extend(shapes);
});
ui.vertical_centered(|ui| {
ui.add(crate::egui_github_link_file!());
});
}
}
1 change: 1 addition & 0 deletions crates/egui_demo_lib/src/demo/demo_app_windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ impl Default for Demos {
Box::<super::code_example::CodeExample>::default(),
Box::<super::context_menu::ContextMenus>::default(),
Box::<super::dancing_strings::DancingStrings>::default(),
Box::<super::dancing_trans_strings::DancingStrings>::default(),
Box::<super::drag_and_drop::DragAndDropDemo>::default(),
Box::<super::extra_viewport::ExtraViewport>::default(),
Box::<super::font_book::FontBook>::default(),
Expand Down
1 change: 1 addition & 0 deletions crates/egui_demo_lib/src/demo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod code_editor;
pub mod code_example;
pub mod context_menu;
pub mod dancing_strings;
pub mod dancing_trans_strings;
pub mod demo_app_windows;
pub mod drag_and_drop;
pub mod extra_viewport;
Expand Down
68 changes: 66 additions & 2 deletions crates/epaint/benches/benchmark.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};

use epaint::*;
use epaint::{tessellator::Path, *};

fn single_dashed_lines(c: &mut Criterion) {
c.bench_function("single_dashed_lines", move |b| {
Expand Down Expand Up @@ -72,10 +72,74 @@ fn tessellate_circles(c: &mut Criterion) {
});
}

fn thick_line_solid(c: &mut Criterion) {
c.bench_function("thick_solid_line", move |b| {
let line = [pos2(0.0, 0.0), pos2(50.0, 0.0), pos2(100.0, 1.0)];
let mut path = Path::default();
path.add_open_points(&line);

b.iter(|| {
let mut mesh = Mesh::default();
path.stroke_closed(1.5, &Stroke::new(2.0, Color32::RED).into(), &mut mesh);

black_box(mesh);
});
});
}

fn thick_large_line_solid(c: &mut Criterion) {
c.bench_function("thick_large_solid_line", move |b| {
let line = (0..1000).map(|i| pos2(i as f32, 10.0)).collect::<Vec<_>>();
let mut path = Path::default();
path.add_open_points(&line);

b.iter(|| {
let mut mesh = Mesh::default();
path.stroke_closed(1.5, &Stroke::new(2.0, Color32::RED).into(), &mut mesh);

black_box(mesh);
});
});
}

fn thin_line_solid(c: &mut Criterion) {
c.bench_function("thin_solid_line", move |b| {
let line = [pos2(0.0, 0.0), pos2(50.0, 0.0), pos2(100.0, 1.0)];
let mut path = Path::default();
path.add_open_points(&line);

b.iter(|| {
let mut mesh = Mesh::default();
path.stroke_closed(1.5, &Stroke::new(0.5, Color32::RED).into(), &mut mesh);

black_box(mesh);
});
});
}

fn thin_large_line_solid(c: &mut Criterion) {
c.bench_function("thin_large_solid_line", move |b| {
let line = (0..1000).map(|i| pos2(i as f32, 10.0)).collect::<Vec<_>>();
let mut path = Path::default();
path.add_open_points(&line);

b.iter(|| {
let mut mesh = Mesh::default();
path.stroke_closed(1.5, &Stroke::new(0.5, Color32::RED).into(), &mut mesh);

black_box(mesh);
});
});
}

murl-digital marked this conversation as resolved.
Show resolved Hide resolved
criterion_group!(
benches,
single_dashed_lines,
many_dashed_lines,
tessellate_circles
tessellate_circles,
thick_line_solid,
thick_large_line_solid,
thin_line_solid,
thin_large_line_solid
);
criterion_main!(benches);
Loading
Loading