1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-29 21:00:03 -04:00

Merge branch 'master' into cache_galley_lines

This commit is contained in:
Hubert Głuchowski
2024-12-19 23:21:09 +01:00
committed by GitHub
138 changed files with 2386 additions and 1394 deletions

View File

@@ -207,17 +207,21 @@ impl CubicBezierShape {
/// B.x = (P3.x - 3 * P2.x + 3 * P1.x - P0.x) * t^3 + (3 * P2.x - 6 * P1.x + 3 * P0.x) * t^2 + (3 * P1.x - 3 * P0.x) * t + P0.x
/// B.y = (P3.y - 3 * P2.y + 3 * P1.y - P0.y) * t^3 + (3 * P2.y - 6 * P1.y + 3 * P0.y) * t^2 + (3 * P1.y - 3 * P0.y) * t + P0.y
/// Combine the above three equations and iliminate B.x and B.y, we get:
/// ```text
/// t^3 * ( (P3.x - 3*P2.x + 3*P1.x - P0.x) * (P3.y - P0.y) - (P3.y - 3*P2.y + 3*P1.y - P0.y) * (P3.x - P0.x))
/// + t^2 * ( (3 * P2.x - 6 * P1.x + 3 * P0.x) * (P3.y - P0.y) - (3 * P2.y - 6 * P1.y + 3 * P0.y) * (P3.x - P0.x))
/// + t^1 * ( (3 * P1.x - 3 * P0.x) * (P3.y - P0.y) - (3 * P1.y - 3 * P0.y) * (P3.x - P0.x))
/// + (P0.x * (P3.y - P0.y) - P0.y * (P3.x - P0.x)) + P0.x * (P0.y - P3.y) + P0.y * (P3.x - P0.x)
/// = 0
/// or a * t^3 + b * t^2 + c * t + d = 0
/// ```
/// or `a * t^3 + b * t^2 + c * t + d = 0`
///
/// let x = t - b / (3 * a), then we have:
/// ```text
/// x^3 + p * x + q = 0, where:
/// p = (3.0 * a * c - b^2) / (3.0 * a^2)
/// q = (2.0 * b^3 - 9.0 * a * b * c + 27.0 * a^2 * d) / (27.0 * a^3)
/// ```
///
/// when p > 0, there will be one real root, two complex roots
/// when p = 0, there will be two real roots, when p=q=0, there will be three real roots but all 0.

View File

@@ -154,8 +154,10 @@ impl ColorImage {
let max_x = (region.max.x * pixels_per_point) as usize;
let min_y = (region.min.y * pixels_per_point) as usize;
let max_y = (region.max.y * pixels_per_point) as usize;
assert!(min_x <= max_x);
assert!(min_y <= max_y);
assert!(
min_x <= max_x && min_y <= max_y,
"Screenshot region is invalid: {region:?}"
);
let width = max_x - min_x;
let height = max_y - min_y;
let mut output = Vec::with_capacity(width * height);

View File

@@ -143,33 +143,3 @@ pub enum Primitive {
/// Was epaint compiled with the `rayon` feature?
pub const HAS_RAYON: bool = cfg!(feature = "rayon");
// ---------------------------------------------------------------------------
mod profiling_scopes {
#![allow(unused_macros)]
#![allow(unused_imports)]
/// Profiling macro for feature "puffin"
macro_rules! profile_function {
($($arg: tt)*) => {
#[cfg(feature = "puffin")]
#[cfg(not(target_arch = "wasm32"))] // Disabled on web because of the coarse 1ms clock resolution there.
puffin::profile_function!($($arg)*);
};
}
pub(crate) use profile_function;
/// Profiling macro for feature "puffin"
macro_rules! profile_scope {
($($arg: tt)*) => {
#[cfg(feature = "puffin")]
#[cfg(not(target_arch = "wasm32"))] // Disabled on web because of the coarse 1ms clock resolution there.
puffin::profile_scope!($($arg)*);
};
}
pub(crate) use profile_scope;
}
#[allow(unused_imports)]
pub(crate) use profiling_scopes::{profile_function, profile_scope};

View File

@@ -85,7 +85,7 @@ impl Mesh {
/// Are all indices within the bounds of the contained vertices?
pub fn is_valid(&self) -> bool {
crate::profile_function!();
profiling::function_scope!();
if let Ok(n) = u32::try_from(self.vertices.len()) {
self.indices.iter().all(|&i| i < n)
@@ -111,7 +111,7 @@ impl Mesh {
///
/// Panics when `other` mesh has a different texture.
pub fn append(&mut self, other: Self) {
crate::profile_function!();
profiling::function_scope!();
debug_assert!(other.is_valid());
if self.is_empty() {

View File

@@ -161,10 +161,15 @@ where
impl From<Stroke> for PathStroke {
fn from(value: Stroke) -> Self {
Self {
width: value.width,
color: ColorMode::Solid(value.color),
kind: StrokeKind::default(),
if value.is_empty() {
// Important, since we use the stroke color when doing feathering of the fill!
Self::NONE
} else {
Self {
width: value.width,
color: ColorMode::Solid(value.color),
kind: StrokeKind::default(),
}
}
}
}

View File

@@ -502,6 +502,8 @@ impl Path {
/// Calling this may reverse the vertices in the path if they are wrong winding order.
///
/// The preferred winding order is clockwise.
///
/// The stroke colors is used for color-correct feathering.
pub fn fill(&mut self, feathering: f32, color: Color32, stroke: &PathStroke, out: &mut Mesh) {
fill_closed_path(feathering, &mut self.0, color, stroke, out);
}
@@ -918,7 +920,7 @@ fn stroke_path(
) {
let n = path.len() as u32;
if stroke.width <= 0.0 || stroke.color == ColorMode::TRANSPARENT || n < 2 {
if stroke.is_empty() || n < 2 {
return;
}
@@ -1277,6 +1279,11 @@ impl Tessellator {
((point * self.pixels_per_point - 0.5).round() + 0.5) / self.pixels_per_point
}
#[inline(always)]
pub fn round_pos_to_pixel(&self, pos: Pos2) -> Pos2 {
pos2(self.round_to_pixel(pos.x), self.round_to_pixel(pos.y))
}
#[inline(always)]
pub fn round_pos_to_pixel_center(&self, pos: Pos2) -> Pos2 {
pos2(
@@ -1363,7 +1370,7 @@ impl Tessellator {
self.tessellate_ellipse(ellipse, out);
}
Shape::Mesh(mesh) => {
crate::profile_scope!("mesh");
profiling::scope!("mesh");
if self.options.validate_meshes && !mesh.is_valid() {
debug_assert!(false, "Invalid Mesh in Shape::Mesh");
@@ -1596,7 +1603,7 @@ impl Tessellator {
return;
}
crate::profile_function!();
profiling::function_scope!();
let PathShape {
points,
@@ -1702,6 +1709,20 @@ impl Tessellator {
self.tessellate_line(line, stroke, out); // …and forth
}
} else {
let rect = if !stroke.is_empty() && stroke.width < self.feathering {
// Very thin rectangle strokes create extreme aliasing when they move around.
// We can fix that by rounding the rectangle corners to pixel centers.
// TODO(#5164): maybe do this for all shapes and stroke sizes
// TODO(emilk): since we use StrokeKind::Outside, we should probably round the
// corners after offsetting them with half the stroke width (see `translate_stroke_point`).
Rect {
min: self.round_pos_to_pixel_center(rect.min),
max: self.round_pos_to_pixel_center(rect.max),
}
} else {
rect
};
let path = &mut self.scratchpad_path;
path.clear();
path::rounded_rectangle(&mut self.scratchpad_points, rect, rounding);
@@ -1979,7 +2000,7 @@ impl Tessellator {
/// A list of clip rectangles with matching [`Mesh`].
#[allow(unused_mut)]
pub fn tessellate_shapes(&mut self, mut shapes: Vec<ClippedShape>) -> Vec<ClippedPrimitive> {
crate::profile_function!();
profiling::function_scope!();
#[cfg(feature = "rayon")]
if self.options.parallel_tessellation {
@@ -1989,7 +2010,7 @@ impl Tessellator {
let mut clipped_primitives: Vec<ClippedPrimitive> = Vec::default();
{
crate::profile_scope!("tessellate");
profiling::scope!("tessellate");
for clipped_shape in shapes {
self.tessellate_clipped_shape(clipped_shape, &mut clipped_primitives);
}
@@ -2026,7 +2047,7 @@ impl Tessellator {
/// then replace the original shape with their tessellated meshes.
#[cfg(feature = "rayon")]
fn parallel_tessellation_of_large_shapes(&self, shapes: &mut [ClippedShape]) {
crate::profile_function!();
profiling::function_scope!();
use rayon::prelude::*;
@@ -2056,7 +2077,7 @@ impl Tessellator {
.enumerate()
.filter(|(_, clipped_shape)| should_parallelize(&clipped_shape.shape))
.map(|(index, clipped_shape)| {
crate::profile_scope!("tessellate_big_shape");
profiling::scope!("tessellate_big_shape");
// TODO(emilk): reuse tessellator in a thread local
let mut tessellator = (*self).clone();
let mut mesh = Mesh::default();
@@ -2065,7 +2086,7 @@ impl Tessellator {
})
.collect();
crate::profile_scope!("distribute results", tessellated.len().to_string());
profiling::scope!("distribute results", tessellated.len().to_string());
for (index, mesh) in tessellated {
shapes[index].shape = Shape::Mesh(mesh);
}

View File

@@ -66,6 +66,7 @@ impl TextureHandle {
}
/// Assign a new image to an existing texture.
#[allow(clippy::needless_pass_by_ref_mut)] // Intentionally hide interiority of mutability
pub fn set(&mut self, image: impl Into<ImageData>, options: TextureOptions) {
self.tex_mngr
.write()
@@ -73,6 +74,7 @@ impl TextureHandle {
}
/// Assign a new image to a subregion of the whole texture.
#[allow(clippy::needless_pass_by_ref_mut)] // Intentionally hide interiority of mutability
pub fn set_partial(
&mut self,
pos: [usize; 2],