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 28 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
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 0 additions & 1 deletion crates/ecolor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ extra_debug_asserts = []
## Always enable additional checks.
extra_asserts = []


[dependencies]
#! ### Optional dependencies

Expand Down
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
4 changes: 3 additions & 1 deletion crates/egui_demo_lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ syntect = ["egui_extras/syntect"]


[dependencies]
egui = { workspace = true, default-features = false }
egui = { workspace = true, default-features = false, features = ["color-hex"] }
egui_extras = { workspace = true, features = ["default"] }
egui_plot = { workspace = true, features = ["default"] }

once_cell = "1.19"

log.workspace = true
unicode_names2 = { version = "0.6.0", default-features = false } # this old version has fewer dependencies

Expand Down
53 changes: 50 additions & 3 deletions crates/egui_demo_lib/src/demo/dancing_strings.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
use egui::{containers::*, *};
use egui::{containers::*, epaint::PathStroke, *};
use once_cell::sync::Lazy;

static GRADIENT: Lazy<[Color32; 5]> = Lazy::new(|| {
[
hex_color!("#5BCEFA"),
hex_color!("#F5A9B8"),
Color32::WHITE,
hex_color!("#F5A9B8"),
hex_color!("#5BCEFA"),
]
});

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

impl super::Demo for DancingStrings {
fn name(&self) -> &'static str {
Expand All @@ -28,6 +41,10 @@ impl super::View for DancingStrings {
Color32::from_black_alpha(240)
};

ui.horizontal(|ui| ui.checkbox(&mut self.colors, "Show Colors"));

ui.separator();

Frame::canvas(ui.style()).show(ui, |ui| {
ui.ctx().request_repaint();
let time = ui.input(|i| i.time);
Expand Down Expand Up @@ -55,7 +72,37 @@ impl super::View for DancingStrings {
.collect();

let thickness = 10.0 / mode as f32;
shapes.push(epaint::Shape::line(points, Stroke::new(thickness, color)));
shapes.push(epaint::Shape::line(
points,
if self.colors {
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 amp = (time * speed * mode).sin() / mode;
let sin = amp * (time * std::f64::consts::TAU / 2.0 * mode).sin();

let value = x * sin + y * sin;

let color = if value < 0.2 {
GRADIENT[0]
} else if value < 0.4 {
GRADIENT[1]
} else if value < 0.6 {
GRADIENT[2]
} else if value < 0.8 {
GRADIENT[3]
} else {
GRADIENT[4]
};

Color32::from_rgba_premultiplied(color[0], color[1], color[2], color[3])
})
} else {
PathStroke::new(thickness, color)
},
));
}

ui.painter().extend(shapes);
Expand Down
160 changes: 158 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,166 @@ 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
fn thick_line_uv(c: &mut Criterion) {
c.bench_function("thick_uv_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,
&PathStroke::new_uv(2.0, |_, p| {
black_box(p * 2.0);
Color32::RED
}),
&mut mesh,
);

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

fn thick_large_line_uv(c: &mut Criterion) {
c.bench_function("thick_large_uv_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,
&PathStroke::new_uv(2.0, |_, p| {
black_box(p * 2.0);
Color32::RED
}),
&mut mesh,
);

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

fn thin_line_uv(c: &mut Criterion) {
c.bench_function("thin_uv_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,
&PathStroke::new_uv(2.0, |_, p| {
black_box(p * 2.0);
Color32::RED
}),
&mut mesh,
);

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

fn thin_large_line_uv(c: &mut Criterion) {
c.bench_function("thin_large_uv_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,
&PathStroke::new_uv(2.0, |_, p| {
black_box(p * 2.0);
Color32::RED
}),
&mut mesh,
);

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

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,
thick_line_uv,
thick_large_line_uv,
thin_line_uv,
thin_large_line_uv
);
criterion_main!(benches);
Loading
Loading