Rename PaintCmd to Shape

This commit is contained in:
Emil Ernerfeldt 2021-01-10 11:43:01 +01:00
parent a0b0f36d29
commit fb2317c993
33 changed files with 225 additions and 235 deletions

View file

@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* Center window titles. * Center window titles.
* Tweak size and alignment of some emojis to match other text. * Tweak size and alignment of some emojis to match other text.
* Rename `PaintCmd` to `Shape`.
* Rename feature "serde" to "persistence". * Rename feature "serde" to "persistence".
### Fixed 🐛 ### Fixed 🐛
@ -163,7 +164,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* Refactored the interface for `egui::app::App`. * Refactored the interface for `egui::app::App`.
* Windows are now constrained to the screen. * Windows are now constrained to the screen.
* `Context::begin_frame()` no longer returns a `Ui`. Instead put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`. * `Context::begin_frame()` no longer returns a `Ui`. Instead put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`.
* `Context::end_frame()` now returns paint commands that need to be converted to triangles with `Context::tessellate()`. * `Context::end_frame()` now returns shapes that need to be converted to triangles with `Context::tessellate()`.
* Anti-aliasing is now off by default in debug builds. * Anti-aliasing is now off by default in debug builds.
### Removed 🔥 ### Removed 🔥

View file

@ -173,8 +173,8 @@ loop {
let raw_input: egui::RawInput = my_integration.gather_input(); let raw_input: egui::RawInput = my_integration.gather_input();
egui_ctx.begin_frame(raw_input); egui_ctx.begin_frame(raw_input);
my_app.ui(&mut egui_ctx); // add panels, windows and widgets to `egui_ctx` here my_app.ui(&mut egui_ctx); // add panels, windows and widgets to `egui_ctx` here
let (output, paint_commands) = egui_ctx.end_frame(); let (output, shapes) = egui_ctx.end_frame();
let paint_jobs = egui_ctx.tessellate(paint_commands); // create triangles to paint let paint_jobs = egui_ctx.tessellate(shapes); // create triangles to paint
my_integration.paint(paint_jobs); my_integration.paint(paint_jobs);
my_integration.set_cursor_icon(output.cursor_icon); my_integration.set_cursor_icon(output.cursor_icon);
// Also see `egui::Output` for more // Also see `egui::Output` for more

View file

@ -1,7 +1,7 @@
use std::hash::Hash; use std::hash::Hash;
use crate::{ use crate::{
paint::{PaintCmd, TextStyle}, paint::{Shape, TextStyle},
widgets::Label, widgets::Label,
*, *,
}; };
@ -119,7 +119,7 @@ pub(crate) fn paint_icon(ui: &mut Ui, openness: f32, response: &Response) {
*p = rect.center() + rotation * (*p - rect.center()); *p = rect.center() + rotation * (*p - rect.center());
} }
ui.painter().add(PaintCmd::closed_line(points, stroke)); ui.painter().add(Shape::closed_line(points, stroke));
} }
/// A header which can be collapsed/expanded, revealing a contained [`Ui`] region. /// A header which can be collapsed/expanded, revealing a contained [`Ui`] region.
@ -203,7 +203,7 @@ impl CollapsingHeader {
state.toggle(ui); state.toggle(ui);
} }
let bg_index = ui.painter().add(PaintCmd::Noop); let bg_index = ui.painter().add(Shape::Noop);
{ {
let (mut icon_rect, _) = ui.style().spacing.icon_rectangles(header_response.rect); let (mut icon_rect, _) = ui.style().spacing.icon_rectangles(header_response.rect);
@ -229,7 +229,7 @@ impl CollapsingHeader {
painter.set( painter.set(
bg_index, bg_index,
PaintCmd::Rect { Shape::Rect {
rect: header_response.rect, rect: header_response.rect,
corner_radius: ui.style().interact(&header_response).corner_radius, corner_radius: ui.style().interact(&header_response).corner_radius,
fill: ui.style().interact(&header_response).bg_fill, fill: ui.style().interact(&header_response).bg_fill,

View file

@ -1,4 +1,4 @@
use crate::{paint::PaintCmd, style::WidgetVisuals, *}; use crate::{paint::Shape, style::WidgetVisuals, *};
/// A drop-down selection menu with a descriptive label. /// A drop-down selection menu with a descriptive label.
/// ///
@ -119,7 +119,7 @@ fn button_frame(
let margin = ui.style().spacing.button_padding; let margin = ui.style().spacing.button_padding;
let outer_rect_bounds = ui.available_rect_before_wrap(); let outer_rect_bounds = ui.available_rect_before_wrap();
let inner_rect = outer_rect_bounds.shrink2(margin); let inner_rect = outer_rect_bounds.shrink2(margin);
let where_to_put_background = ui.painter().add(PaintCmd::Noop); let where_to_put_background = ui.painter().add(Shape::Noop);
let mut content_ui = ui.child_ui(inner_rect, *ui.layout()); let mut content_ui = ui.child_ui(inner_rect, *ui.layout());
add_contents(&mut content_ui); add_contents(&mut content_ui);
@ -131,7 +131,7 @@ fn button_frame(
ui.painter().set( ui.painter().set(
where_to_put_background, where_to_put_background,
PaintCmd::Rect { Shape::Rect {
rect: outer_rect, rect: outer_rect,
corner_radius: visuals.corner_radius, corner_radius: visuals.corner_radius,
fill: visuals.bg_fill, fill: visuals.bg_fill,
@ -149,7 +149,7 @@ fn paint_icon(painter: &Painter, rect: Rect, visuals: &WidgetVisuals) {
rect.center(), rect.center(),
vec2(rect.width() * 0.7, rect.height() * 0.45), vec2(rect.width() * 0.7, rect.height() * 0.45),
); );
painter.add(PaintCmd::closed_line( painter.add(Shape::closed_line(
vec![rect.left_top(), rect.right_top(), rect.center_bottom()], vec![rect.left_top(), rect.right_top(), rect.center_bottom()],
visuals.fg_stroke, visuals.fg_stroke,
)); ));

View file

@ -1,6 +1,6 @@
//! Frame container //! Frame container
use crate::{layers::PaintCmdIdx, paint::*, *}; use crate::{layers::ShapeIdx, paint::*, *};
/// Adds a rectangular frame and background to some [`Ui`]. /// Adds a rectangular frame and background to some [`Ui`].
#[derive(Clone, Copy, Debug, Default, PartialEq)] #[derive(Clone, Copy, Debug, Default, PartialEq)]
@ -95,13 +95,13 @@ impl Frame {
pub struct Prepared { pub struct Prepared {
pub frame: Frame, pub frame: Frame,
outer_rect_bounds: Rect, outer_rect_bounds: Rect,
where_to_put_background: PaintCmdIdx, where_to_put_background: ShapeIdx,
pub content_ui: Ui, pub content_ui: Ui,
} }
impl Frame { impl Frame {
pub fn begin(self, ui: &mut Ui) -> Prepared { pub fn begin(self, ui: &mut Ui) -> Prepared {
let where_to_put_background = ui.painter().add(PaintCmd::Noop); let where_to_put_background = ui.painter().add(Shape::Noop);
let outer_rect_bounds = ui.available_rect_before_wrap(); let outer_rect_bounds = ui.available_rect_before_wrap();
let inner_rect = outer_rect_bounds.shrink2(self.margin); let inner_rect = outer_rect_bounds.shrink2(self.margin);
let content_ui = ui.child_ui(inner_rect, *ui.layout()); let content_ui = ui.child_ui(inner_rect, *ui.layout());
@ -141,7 +141,7 @@ impl Prepared {
.. ..
} = self; } = self;
let frame_cmd = PaintCmd::Rect { let frame_shape = Shape::Rect {
rect: outer_rect, rect: outer_rect,
corner_radius: frame.corner_radius, corner_radius: frame.corner_radius,
fill: frame.fill, fill: frame.fill,
@ -149,13 +149,13 @@ impl Prepared {
}; };
if frame.shadow == Default::default() { if frame.shadow == Default::default() {
ui.painter().set(where_to_put_background, frame_cmd); ui.painter().set(where_to_put_background, frame_shape);
} else { } else {
let shadow = frame.shadow.tessellate(outer_rect, frame.corner_radius); let shadow = frame.shadow.tessellate(outer_rect, frame.corner_radius);
let shadow = PaintCmd::Triangles(shadow); let shadow = Shape::Triangles(shadow);
ui.painter().set( ui.painter().set(
where_to_put_background, where_to_put_background,
PaintCmd::Vec(vec![shadow, frame_cmd]), Shape::Vec(vec![shadow, frame_shape]),
) )
}; };

View file

@ -284,7 +284,7 @@ impl Resize {
if self.with_stroke && corner_response.is_some() { if self.with_stroke && corner_response.is_some() {
let rect = Rect::from_min_size(content_ui.min_rect().left_top(), state.desired_size); let rect = Rect::from_min_size(content_ui.min_rect().left_top(), state.desired_size);
let rect = rect.expand(2.0); // breathing room for content let rect = rect.expand(2.0); // breathing room for content
ui.painter().add(paint::PaintCmd::Rect { ui.painter().add(paint::Shape::Rect {
rect, rect,
corner_radius: 3.0, corner_radius: 3.0,
fill: Default::default(), fill: Default::default(),

View file

@ -325,7 +325,7 @@ impl Prepared {
let visuals = ui.style().interact(&response); let visuals = ui.style().interact(&response);
ui.painter().add(paint::PaintCmd::Rect { ui.painter().add(paint::Shape::Rect {
rect: outer_scroll_rect, rect: outer_scroll_rect,
corner_radius, corner_radius,
fill: ui.style().visuals.dark_bg_color, fill: ui.style().visuals.dark_bg_color,
@ -334,7 +334,7 @@ impl Prepared {
// stroke: visuals.bg_stroke, // stroke: visuals.bg_stroke,
}); });
ui.painter().add(paint::PaintCmd::Rect { ui.painter().add(paint::Shape::Rect {
rect: handle_rect.expand(-2.0), rect: handle_rect.expand(-2.0),
corner_radius, corner_radius,
fill: visuals.fg_fill, fill: visuals.fg_fill,

View file

@ -623,7 +623,7 @@ fn paint_frame_interaction(
points.push(pos2(max.x, min.y + cr)); points.push(pos2(max.x, min.y + cr));
points.push(pos2(max.x, max.y - cr)); points.push(pos2(max.x, max.y - cr));
} }
ui.painter().add(PaintCmd::line(points, visuals.bg_stroke)); ui.painter().add(Shape::line(points, visuals.bg_stroke));
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View file

@ -592,10 +592,10 @@ impl Context {
/// Call at the end of each frame. /// Call at the end of each frame.
/// Returns what has happened this frame (`Output`) as well as what you need to paint. /// Returns what has happened this frame (`Output`) as well as what you need to paint.
/// You can transform the returned paint commands into triangles with a call to /// You can transform the returned shapes into triangles with a call to
/// `Context::tessellate`. /// `Context::tessellate`.
#[must_use] #[must_use]
pub fn end_frame(&self) -> (Output, Vec<(Rect, PaintCmd)>) { pub fn end_frame(&self) -> (Output, Vec<(Rect, Shape)>) {
if self.input.wants_repaint() { if self.input.wants_repaint() {
self.request_repaint(); self.request_repaint();
} }
@ -608,25 +608,21 @@ impl Context {
output.needs_repaint = true; output.needs_repaint = true;
} }
let paint_commands = self.drain_paint_lists(); let shapes = self.drain_paint_lists();
(output, paint_commands) (output, shapes)
} }
fn drain_paint_lists(&self) -> Vec<(Rect, PaintCmd)> { fn drain_paint_lists(&self) -> Vec<(Rect, Shape)> {
let memory = self.memory(); let memory = self.memory();
self.graphics().drain(memory.areas.order()).collect() self.graphics().drain(memory.areas.order()).collect()
} }
/// Tessellate the given paint commands into triangle meshes. /// Tessellate the given shapes into triangle meshes.
pub fn tessellate(&self, paint_commands: Vec<(Rect, PaintCmd)>) -> PaintJobs { pub fn tessellate(&self, shapes: Vec<(Rect, Shape)>) -> PaintJobs {
let mut tessellation_options = self.memory().options.tessellation_options; let mut tessellation_options = self.memory().options.tessellation_options;
tessellation_options.aa_size = 1.0 / self.pixels_per_point(); tessellation_options.aa_size = 1.0 / self.pixels_per_point();
let paint_stats = PaintStats::from_paint_commands(&paint_commands); // TODO: internal allocations let paint_stats = PaintStats::from_shapes(&shapes); // TODO: internal allocations
let paint_jobs = tessellator::tessellate_paint_commands( let paint_jobs = tessellator::tessellate_shapes(shapes, tessellation_options, self.fonts());
paint_commands,
tessellation_options,
self.fonts(),
);
*self.paint_stats.lock() = paint_stats.with_paint_jobs(&paint_jobs); *self.paint_stats.lock() = paint_stats.with_paint_jobs(&paint_jobs);
paint_jobs paint_jobs
} }

View file

@ -1,6 +1,6 @@
//! uis for egui types. //! uis for egui types.
use crate::{ use crate::{
paint::{self, PaintCmd, Texture, Triangles}, paint::{self, Shape, Texture, Triangles},
*, *,
}; };
@ -25,7 +25,7 @@ impl Texture {
[pos2(0.0, 0.0), pos2(1.0, 1.0)].into(), [pos2(0.0, 0.0), pos2(1.0, 1.0)].into(),
Color32::WHITE, Color32::WHITE,
); );
ui.painter().add(PaintCmd::triangles(triangles)); ui.painter().add(Shape::triangles(triangles));
let (tex_w, tex_h) = (self.width as f32, self.height as f32); let (tex_w, tex_h) = (self.width as f32, self.height as f32);
@ -49,7 +49,7 @@ impl Texture {
); );
let mut triangles = Triangles::default(); let mut triangles = Triangles::default();
triangles.add_rect_with_uv(zoom_rect, uv_rect, Color32::WHITE); triangles.add_rect_with_uv(zoom_rect, uv_rect, Color32::WHITE);
ui.painter().add(PaintCmd::triangles(triangles)); ui.painter().add(Shape::triangles(triangles));
}); });
} }
} }

View file

@ -1,6 +1,6 @@
use ahash::AHashMap; use ahash::AHashMap;
use crate::{math::Rect, paint::PaintCmd, Id, *}; use crate::{math::Rect, paint::Shape, Id, *};
/// Different layer categories /// Different layer categories
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] #[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
@ -70,47 +70,48 @@ impl LayerId {
} }
} }
/// A unique identifier of a specific [`PaintCmd`] in a [`PaintList`]. /// A unique identifier of a specific [`Shape`] in a [`PaintList`].
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
pub struct PaintCmdIdx(usize); pub struct ShapeIdx(usize);
/// A list of [`PaintCmd`]s paired with a clip rectangle. /// A list of [`Shape`]s paired with a clip rectangle.
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct PaintList(Vec<(Rect, PaintCmd)>); pub struct PaintList(Vec<(Rect, Shape)>);
impl PaintList { impl PaintList {
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.0.is_empty() self.0.is_empty()
} }
/// Returns the index of the new command that can be used with `PaintList::set`. /// Returns the index of the new [`Shape`] that can be used with `PaintList::set`.
pub fn add(&mut self, clip_rect: Rect, cmd: PaintCmd) -> PaintCmdIdx { pub fn add(&mut self, clip_rect: Rect, shape: Shape) -> ShapeIdx {
let idx = PaintCmdIdx(self.0.len()); let idx = ShapeIdx(self.0.len());
self.0.push((clip_rect, cmd)); self.0.push((clip_rect, shape));
idx idx
} }
pub fn extend(&mut self, clip_rect: Rect, mut cmds: Vec<PaintCmd>) { pub fn extend(&mut self, clip_rect: Rect, mut shapes: Vec<Shape>) {
self.0.extend(cmds.drain(..).map(|cmd| (clip_rect, cmd))) self.0
.extend(shapes.drain(..).map(|shape| (clip_rect, shape)))
} }
/// Modify an existing command. /// Modify an existing [`Shape`].
/// ///
/// Sometimes you want to paint a frame behind some contents, but don't know how large the frame needs to be /// Sometimes you want to paint a frame behind some contents, but don't know how large the frame needs to be
/// until the contents have been added, and therefor also painted to the `PaintList`. /// until the contents have been added, and therefor also painted to the `PaintList`.
/// ///
/// The solution is to allocate a `PaintCmd` using `let idx = paint_list.add(cr, PaintCmd::Noop);` /// The solution is to allocate a `Shape` using `let idx = paint_list.add(cr, Shape::Noop);`
/// and then later setting it using `paint_list.set(idx, cr, frame);`. /// and then later setting it using `paint_list.set(idx, cr, frame);`.
pub fn set(&mut self, idx: PaintCmdIdx, clip_rect: Rect, cmd: PaintCmd) { pub fn set(&mut self, idx: ShapeIdx, clip_rect: Rect, shape: Shape) {
assert!(idx.0 < self.0.len()); assert!(idx.0 < self.0.len());
self.0[idx.0] = (clip_rect, cmd); self.0[idx.0] = (clip_rect, shape);
} }
/// Translate each paint-command and clip rectangle by this much, in-place /// Translate each [`Shape`] and clip rectangle by this much, in-place
pub fn translate(&mut self, delta: Vec2) { pub fn translate(&mut self, delta: Vec2) {
for (clip_rect, cmd) in &mut self.0 { for (clip_rect, shape) in &mut self.0 {
*clip_rect = clip_rect.translate(delta); *clip_rect = clip_rect.translate(delta);
cmd.translate(delta); shape.translate(delta);
} }
} }
} }
@ -128,8 +129,8 @@ impl GraphicLayers {
pub fn drain( pub fn drain(
&mut self, &mut self,
area_order: &[LayerId], area_order: &[LayerId],
) -> impl ExactSizeIterator<Item = (Rect, PaintCmd)> { ) -> impl ExactSizeIterator<Item = (Rect, Shape)> {
let mut all_commands: Vec<_> = Default::default(); let mut all_shapes: Vec<_> = Default::default();
for &order in &Order::ALL { for &order in &Order::ALL {
let order_map = &mut self.0[order as usize]; let order_map = &mut self.0[order as usize];
@ -142,18 +143,18 @@ impl GraphicLayers {
// First do the layers part of area_order: // First do the layers part of area_order:
for layer_id in area_order { for layer_id in area_order {
if layer_id.order == order { if layer_id.order == order {
if let Some(commands) = order_map.get_mut(&layer_id.id) { if let Some(shapes) = order_map.get_mut(&layer_id.id) {
all_commands.extend(commands.0.drain(..)); all_shapes.extend(shapes.0.drain(..));
} }
} }
} }
// Also draw areas that are missing in `area_order`: // Also draw areas that are missing in `area_order`:
for commands in order_map.values_mut() { for shapes in order_map.values_mut() {
all_commands.extend(commands.0.drain(..)); all_shapes.extend(shapes.0.drain(..));
} }
} }
all_commands.into_iter() all_shapes.into_iter()
} }
} }

View file

@ -26,8 +26,8 @@
//! let raw_input: egui::RawInput = my_integration.gather_input(); //! let raw_input: egui::RawInput = my_integration.gather_input();
//! egui_ctx.begin_frame(raw_input); //! egui_ctx.begin_frame(raw_input);
//! my_app.ui(&egui_ctx); // add panels, windows and widgets to `egui_ctx` here //! my_app.ui(&egui_ctx); // add panels, windows and widgets to `egui_ctx` here
//! let (output, paint_commands) = egui_ctx.end_frame(); //! let (output, shapes) = egui_ctx.end_frame();
//! let paint_jobs = egui_ctx.tessellate(paint_commands); // create triangles to paint //! let paint_jobs = egui_ctx.tessellate(shapes); // create triangles to paint
//! my_integration.paint(paint_jobs); //! my_integration.paint(paint_jobs);
//! my_integration.set_cursor_icon(output.cursor_icon); //! my_integration.set_cursor_icon(output.cursor_icon);
//! // Also see `egui::Output` for more //! // Also see `egui::Output` for more
@ -108,7 +108,7 @@ pub use {
math::{clamp, lerp, pos2, remap, remap_clamp, vec2, Align, Align2, NumExt, Pos2, Rect, Vec2}, math::{clamp, lerp, pos2, remap, remap_clamp, vec2, Align, Align2, NumExt, Pos2, Rect, Vec2},
memory::Memory, memory::Memory,
paint::{ paint::{
color, Color32, FontDefinitions, FontFamily, PaintCmd, PaintJobs, Rgba, Stroke, TextStyle, color, Color32, FontDefinitions, FontFamily, PaintJobs, Rgba, Shape, Stroke, TextStyle,
Texture, TextureId, Texture, TextureId,
}, },
painter::Painter, painter::Painter,

View file

@ -1,21 +1,21 @@
//! 2D graphics/rendering. Fonts, textures, color, geometry, tessellation etc. //! 2D graphics/rendering. Fonts, textures, color, geometry, tessellation etc.
pub mod color; pub mod color;
pub mod command;
pub mod font; pub mod font;
pub mod fonts; pub mod fonts;
mod galley; mod galley;
mod shadow; mod shadow;
pub mod shape;
pub mod stats; pub mod stats;
pub mod tessellator; pub mod tessellator;
mod texture_atlas; mod texture_atlas;
pub use { pub use {
color::{Color32, Rgba}, color::{Color32, Rgba},
command::{PaintCmd, Stroke},
fonts::{FontDefinitions, FontFamily, Fonts, TextStyle}, fonts::{FontDefinitions, FontFamily, Fonts, TextStyle},
galley::*, galley::*,
shadow::Shadow, shadow::Shadow,
shape::{Shape, Stroke},
stats::PaintStats, stats::PaintStats,
tessellator::{ tessellator::{
PaintJob, PaintJobs, TessellationOptions, TextureId, Triangles, Vertex, WHITE_UV, PaintJob, PaintJobs, TessellationOptions, TextureId, Triangles, Vertex, WHITE_UV,

View file

@ -6,12 +6,12 @@ use {
/// A paint primitive such as a circle or a piece of text. /// A paint primitive such as a circle or a piece of text.
/// Coordinates are all screen space points (not physical pixels). /// Coordinates are all screen space points (not physical pixels).
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum PaintCmd { pub enum Shape {
/// Paint nothing. This can be useful as a placeholder. /// Paint nothing. This can be useful as a placeholder.
Noop, Noop,
/// Recursively nest more paint commands - sometimes a convenience to be able to do. /// Recursively nest more shapes - sometimes a convenience to be able to do.
/// For performance reasons it is better to avoid it. /// For performance reasons it is better to avoid it.
Vec(Vec<PaintCmd>), Vec(Vec<Shape>),
Circle { Circle {
center: Pos2, center: Pos2,
radius: f32, radius: f32,
@ -49,7 +49,7 @@ pub enum PaintCmd {
} }
/// ## Constructors /// ## Constructors
impl PaintCmd { impl Shape {
pub fn line_segment(points: [Pos2; 2], stroke: impl Into<Stroke>) -> Self { pub fn line_segment(points: [Pos2; 2], stroke: impl Into<Stroke>) -> Self {
Self::LineSegment { Self::LineSegment {
points, points,
@ -141,14 +141,14 @@ impl PaintCmd {
} }
/// ## Operations /// ## Operations
impl PaintCmd { impl Shape {
pub fn triangles(triangles: Triangles) -> Self { pub fn triangles(triangles: Triangles) -> Self {
debug_assert!(triangles.is_valid()); debug_assert!(triangles.is_valid());
Self::Triangles(triangles) Self::Triangles(triangles)
} }
pub fn texture_id(&self) -> super::TextureId { pub fn texture_id(&self) -> super::TextureId {
if let PaintCmd::Triangles(triangles) = self { if let Shape::Triangles(triangles) = self {
triangles.texture_id triangles.texture_id
} else { } else {
super::TextureId::Egui super::TextureId::Egui
@ -158,32 +158,32 @@ impl PaintCmd {
/// Translate location by this much, in-place /// Translate location by this much, in-place
pub fn translate(&mut self, delta: Vec2) { pub fn translate(&mut self, delta: Vec2) {
match self { match self {
PaintCmd::Noop => {} Shape::Noop => {}
PaintCmd::Vec(commands) => { Shape::Vec(shapes) => {
for command in commands { for shape in shapes {
command.translate(delta); shape.translate(delta);
} }
} }
PaintCmd::Circle { center, .. } => { Shape::Circle { center, .. } => {
*center += delta; *center += delta;
} }
PaintCmd::LineSegment { points, .. } => { Shape::LineSegment { points, .. } => {
for p in points { for p in points {
*p += delta; *p += delta;
} }
} }
PaintCmd::Path { points, .. } => { Shape::Path { points, .. } => {
for p in points { for p in points {
*p += delta; *p += delta;
} }
} }
PaintCmd::Rect { rect, .. } => { Shape::Rect { rect, .. } => {
*rect = rect.translate(delta); *rect = rect.translate(delta);
} }
PaintCmd::Text { pos, .. } => { Shape::Text { pos, .. } => {
*pos += delta; *pos += delta;
} }
PaintCmd::Triangles(triangles) => { Shape::Triangles(triangles) => {
triangles.translate(delta); triangles.translate(delta);
} }
} }

View file

@ -54,16 +54,16 @@ impl std::ops::AddAssign for AllocInfo {
} }
impl AllocInfo { impl AllocInfo {
// pub fn from_paint_cmd(cmd: &PaintCmd) -> Self { // pub fn from_shape(shape: &Shape) -> Self {
// match cmd { // match shape {
// PaintCmd::Noop // Shape::Noop
// PaintCmd::Vec(commands) => Self::from_paint_commands(commands) // Shape::Vec(shapes) => Self::from_shapes(shapes)
// | PaintCmd::Circle { .. } // | Shape::Circle { .. }
// | PaintCmd::LineSegment { .. } // | Shape::LineSegment { .. }
// | PaintCmd::Rect { .. } => Self::default(), // | Shape::Rect { .. } => Self::default(),
// PaintCmd::Path { points, .. } => Self::from_slice(points), // Shape::Path { points, .. } => Self::from_slice(points),
// PaintCmd::Text { galley, .. } => Self::from_galley(galley), // Shape::Text { galley, .. } => Self::from_galley(galley),
// PaintCmd::Triangles(triangles) => Self::from_triangles(triangles), // Shape::Triangles(triangles) => Self::from_triangles(triangles),
// } // }
// } // }
@ -137,11 +137,11 @@ impl AllocInfo {
#[derive(Clone, Copy, Default)] #[derive(Clone, Copy, Default)]
pub struct PaintStats { pub struct PaintStats {
primitives: AllocInfo, shapes: AllocInfo,
cmd_text: AllocInfo, shape_text: AllocInfo,
cmd_path: AllocInfo, shape_path: AllocInfo,
cmd_mesh: AllocInfo, shape_mesh: AllocInfo,
cmd_vec: AllocInfo, shape_vec: AllocInfo,
/// Number of separate clip rectangles /// Number of separate clip rectangles
jobs: AllocInfo, jobs: AllocInfo,
@ -150,40 +150,39 @@ pub struct PaintStats {
} }
impl PaintStats { impl PaintStats {
pub fn from_paint_commands(paint_commands: &[(Rect, PaintCmd)]) -> Self { pub fn from_shapes(shapes: &[(Rect, Shape)]) -> Self {
let mut stats = Self::default(); let mut stats = Self::default();
stats.cmd_path.element_size = ElementSize::Heterogenous; // nicer display later stats.shape_path.element_size = ElementSize::Heterogenous; // nicer display later
stats.cmd_vec.element_size = ElementSize::Heterogenous; // nicer display later stats.shape_vec.element_size = ElementSize::Heterogenous; // nicer display later
stats.primitives = AllocInfo::from_slice(paint_commands); stats.shapes = AllocInfo::from_slice(shapes);
for (_, cmd) in paint_commands { for (_, shape) in shapes {
stats.add(cmd); stats.add(shape);
} }
stats stats
} }
fn add(&mut self, cmd: &PaintCmd) { fn add(&mut self, shape: &Shape) {
match cmd { match shape {
PaintCmd::Vec(paint_commands) => { Shape::Vec(shapes) => {
// self += PaintStats::from_paint_commands(&paint_commands); // TODO // self += PaintStats::from_shapes(&shapes); // TODO
self.primitives += AllocInfo::from_slice(paint_commands); self.shapes += AllocInfo::from_slice(shapes);
self.cmd_vec += AllocInfo::from_slice(paint_commands); self.shape_vec += AllocInfo::from_slice(shapes);
for cmd in paint_commands { for shape in shapes {
self.add(cmd); self.add(shape);
} }
} }
PaintCmd::Noop Shape::Noop | Shape::Circle { .. } | Shape::LineSegment { .. } | Shape::Rect { .. } => {
| PaintCmd::Circle { .. } Default::default()
| PaintCmd::LineSegment { .. }
| PaintCmd::Rect { .. } => Default::default(),
PaintCmd::Path { points, .. } => {
self.cmd_path += AllocInfo::from_slice(points);
} }
PaintCmd::Text { galley, .. } => { Shape::Path { points, .. } => {
self.cmd_text += AllocInfo::from_galley(galley); self.shape_path += AllocInfo::from_slice(points);
} }
PaintCmd::Triangles(triangles) => { Shape::Text { galley, .. } => {
self.cmd_mesh += AllocInfo::from_triangles(triangles); self.shape_text += AllocInfo::from_galley(galley);
}
Shape::Triangles(triangles) => {
self.shape_mesh += AllocInfo::from_triangles(triangles);
} }
} }
} }
@ -198,10 +197,10 @@ impl PaintStats {
} }
// pub fn total(&self) -> AllocInfo { // pub fn total(&self) -> AllocInfo {
// self.primitives // self.shapes
// + self.cmd_text // + self.shape_text
// + self.cmd_path // + self.shape_path
// + self.cmd_mesh // + self.shape_mesh
// + self.jobs // + self.jobs
// + self.vertices // + self.vertices
// + self.indices // + self.indices
@ -211,7 +210,7 @@ impl PaintStats {
impl PaintStats { impl PaintStats {
pub fn ui(&self, ui: &mut crate::Ui) { pub fn ui(&self, ui: &mut crate::Ui) {
ui.label( ui.label(
"Egui generates intermediate level primitives like circles and text. \ "Egui generates intermediate level shapes like circles and text. \
These are later tessellated into triangles.", These are later tessellated into triangles.",
); );
ui.advance_cursor(10.0); ui.advance_cursor(10.0);
@ -219,24 +218,24 @@ impl PaintStats {
ui.style_mut().body_text_style = TextStyle::Monospace; ui.style_mut().body_text_style = TextStyle::Monospace;
let Self { let Self {
primitives, shapes,
cmd_text, shape_text,
cmd_path, shape_path,
cmd_mesh, shape_mesh,
cmd_vec, shape_vec,
jobs, jobs,
vertices, vertices,
indices, indices,
} = self; } = self;
ui.label("Intermediate:"); ui.label("Intermediate:");
primitives shapes
.label(ui, "primitives") .label(ui, "shapes")
.on_hover_text("Boxes, circles, etc"); .on_hover_text("Boxes, circles, etc");
cmd_text.label(ui, "text"); shape_text.label(ui, "text");
cmd_path.label(ui, "paths"); shape_path.label(ui, "paths");
cmd_mesh.label(ui, "meshes"); shape_mesh.label(ui, "meshes");
cmd_vec.label(ui, "nested"); shape_vec.label(ui, "nested");
ui.advance_cursor(10.0); ui.advance_cursor(10.0);
ui.label("Tessellated:"); ui.label("Tessellated:");

View file

@ -1,6 +1,6 @@
//! Converts graphics primitives into textured triangles. //! Converts graphics primitives into textured triangles.
//! //!
//! This module converts lines, circles, text and more represented by [`PaintCmd`] //! This module converts lines, circles, text and more represented by [`Shape`]
//! into textured triangles represented by [`Triangles`]. //! into textured triangles represented by [`Triangles`].
#![allow(clippy::identity_op)] #![allow(clippy::identity_op)]
@ -687,31 +687,26 @@ impl Tessellator {
} }
} }
/// Tessellate a single [`PaintCmd`] into a [`Triangles`]. /// Tessellate a single [`Shape`] into a [`Triangles`].
/// ///
/// * `command`: the command to tessellate /// * `shape`: the shape to tessellate
/// * `options`: tessellation quality /// * `options`: tessellation quality
/// * `fonts`: font source when tessellating text /// * `fonts`: font source when tessellating text
/// * `out`: where the triangles are put /// * `out`: where the triangles are put
/// * `scratchpad_path`: if you plan to run `tessellate_paint_command` /// * `scratchpad_path`: if you plan to run `tessellate_shape`
/// many times, pass it a reference to the same `Path` to avoid excessive allocations. /// many times, pass it a reference to the same `Path` to avoid excessive allocations.
pub fn tessellate_paint_command( pub fn tessellate_shape(&mut self, fonts: &Fonts, shape: Shape, out: &mut Triangles) {
&mut self,
fonts: &Fonts,
command: PaintCmd,
out: &mut Triangles,
) {
let clip_rect = self.clip_rect; let clip_rect = self.clip_rect;
let options = self.options; let options = self.options;
match command { match shape {
PaintCmd::Noop => {} Shape::Noop => {}
PaintCmd::Vec(vec) => { Shape::Vec(vec) => {
for command in vec { for shape in vec {
self.tessellate_paint_command(fonts, command, out) self.tessellate_shape(fonts, shape, out)
} }
} }
PaintCmd::Circle { Shape::Circle {
center, center,
radius, radius,
fill, fill,
@ -733,20 +728,20 @@ impl Tessellator {
fill_closed_path(&path.0, fill, options, out); fill_closed_path(&path.0, fill, options, out);
stroke_path(&path.0, Closed, stroke, options, out); stroke_path(&path.0, Closed, stroke, options, out);
} }
PaintCmd::Triangles(triangles) => { Shape::Triangles(triangles) => {
if triangles.is_valid() { if triangles.is_valid() {
out.append(triangles); out.append(triangles);
} else { } else {
debug_assert!(false, "Invalid Triangles in PaintCmd::Triangles"); debug_assert!(false, "Invalid Triangles in Shape::Triangles");
} }
} }
PaintCmd::LineSegment { points, stroke } => { Shape::LineSegment { points, stroke } => {
let path = &mut self.scratchpad_path; let path = &mut self.scratchpad_path;
path.clear(); path.clear();
path.add_line_segment(points); path.add_line_segment(points);
stroke_path(&path.0, Open, stroke, options, out); stroke_path(&path.0, Open, stroke, options, out);
} }
PaintCmd::Path { Shape::Path {
points, points,
closed, closed,
fill, fill,
@ -772,7 +767,7 @@ impl Tessellator {
stroke_path(&path.0, typ, stroke, options, out); stroke_path(&path.0, typ, stroke, options, out);
} }
} }
PaintCmd::Rect { Shape::Rect {
rect, rect,
corner_radius, corner_radius,
fill, fill,
@ -786,7 +781,7 @@ impl Tessellator {
}; };
self.tessellate_rect(&rect, out); self.tessellate_rect(&rect, out);
} }
PaintCmd::Text { Shape::Text {
pos, pos,
galley, galley,
text_style, text_style,
@ -872,7 +867,7 @@ impl Tessellator {
let c = chars.next().unwrap(); let c = chars.next().unwrap();
if self.options.coarse_tessellation_culling && !is_line_visible { if self.options.coarse_tessellation_culling && !is_line_visible {
// culling individual lines of text is important, since a single `PaintCmd::Text` // culling individual lines of text is important, since a single `Shape::Text`
// can span hundreds of lines. // can span hundreds of lines.
continue; continue;
} }
@ -899,29 +894,29 @@ impl Tessellator {
} }
} }
/// Turns [`PaintCmd`]:s into sets of triangles. /// Turns [`Shape`]:s into sets of triangles.
/// ///
/// The given commands will be painted back-to-front (painters algorithm). /// The given shapes will be painted back-to-front (painters algorithm).
/// They will be batched together by clip rectangle. /// They will be batched together by clip rectangle.
/// ///
/// * `commands`: the command to tessellate /// * `shapes`: the shape to tessellate
/// * `options`: tessellation quality /// * `options`: tessellation quality
/// * `fonts`: font source when tessellating text /// * `fonts`: font source when tessellating text
/// ///
/// ## Returns /// ## Returns
/// A list of clip rectangles with matching [`Triangles`]. /// A list of clip rectangles with matching [`Triangles`].
pub fn tessellate_paint_commands( pub fn tessellate_shapes(
commands: Vec<(Rect, PaintCmd)>, shapes: Vec<(Rect, Shape)>,
options: TessellationOptions, options: TessellationOptions,
fonts: &Fonts, fonts: &Fonts,
) -> Vec<(Rect, Triangles)> { ) -> Vec<(Rect, Triangles)> {
let mut tessellator = Tessellator::from_options(options); let mut tessellator = Tessellator::from_options(options);
let mut jobs = PaintJobs::default(); let mut jobs = PaintJobs::default();
for (clip_rect, cmd) in commands { for (clip_rect, shape) in shapes {
let start_new_job = match jobs.last() { let start_new_job = match jobs.last() {
None => true, None => true,
Some(job) => job.0 != clip_rect || job.1.texture_id != cmd.texture_id(), Some(job) => job.0 != clip_rect || job.1.texture_id != shape.texture_id(),
}; };
if start_new_job { if start_new_job {
@ -930,15 +925,15 @@ pub fn tessellate_paint_commands(
let out = &mut jobs.last_mut().unwrap().1; let out = &mut jobs.last_mut().unwrap().1;
tessellator.clip_rect = clip_rect; tessellator.clip_rect = clip_rect;
tessellator.tessellate_paint_command(fonts, cmd, out); tessellator.tessellate_shape(fonts, shape, out);
} }
if options.debug_paint_clip_rects { if options.debug_paint_clip_rects {
for (clip_rect, triangles) in &mut jobs { for (clip_rect, triangles) in &mut jobs {
tessellator.clip_rect = Rect::everything(); tessellator.clip_rect = Rect::everything();
tessellator.tessellate_paint_command( tessellator.tessellate_shape(
fonts, fonts,
PaintCmd::Rect { Shape::Rect {
rect: *clip_rect, rect: *clip_rect,
corner_radius: 0.0, corner_radius: 0.0,
fill: Default::default(), fill: Default::default(),

View file

@ -1,7 +1,7 @@
use crate::{ use crate::{
layers::PaintCmdIdx, layers::ShapeIdx,
math::{Align2, Pos2, Rect, Vec2}, math::{Align2, Pos2, Rect, Vec2},
paint::{Fonts, Galley, PaintCmd, Stroke, TextStyle}, paint::{Fonts, Galley, Shape, Stroke, TextStyle},
Color32, CtxRef, LayerId, Color32, CtxRef, LayerId,
}; };
@ -10,7 +10,7 @@ use crate::{
/// All coordinates are screen coordinates in the unit points (one point can consist of many physical pixels). /// All coordinates are screen coordinates in the unit points (one point can consist of many physical pixels).
#[derive(Clone)] #[derive(Clone)]
pub struct Painter { pub struct Painter {
/// Source of fonts and destination of paint commands /// Source of fonts and destination of shapes
ctx: CtxRef, ctx: CtxRef,
/// Where we paint /// Where we paint
@ -106,26 +106,26 @@ impl Painter {
/// It is up to the caller to make sure there is room for this. /// It is up to the caller to make sure there is room for this.
/// Can be used for free painting. /// Can be used for free painting.
/// NOTE: all coordinates are screen coordinates! /// NOTE: all coordinates are screen coordinates!
pub fn add(&self, paint_cmd: PaintCmd) -> PaintCmdIdx { pub fn add(&self, shape: Shape) -> ShapeIdx {
self.ctx self.ctx
.graphics() .graphics()
.list(self.layer_id) .list(self.layer_id)
.add(self.clip_rect, paint_cmd) .add(self.clip_rect, shape)
} }
pub fn extend(&self, cmds: Vec<PaintCmd>) { pub fn extend(&self, shapes: Vec<Shape>) {
self.ctx self.ctx
.graphics() .graphics()
.list(self.layer_id) .list(self.layer_id)
.extend(self.clip_rect, cmds); .extend(self.clip_rect, shapes);
} }
/// Modify an existing command. /// Modify an existing [`Shape`].
pub fn set(&self, idx: PaintCmdIdx, cmd: PaintCmd) { pub fn set(&self, idx: ShapeIdx, shape: Shape) {
self.ctx self.ctx
.graphics() .graphics()
.list(self.layer_id) .list(self.layer_id)
.set(idx, self.clip_rect, cmd) .set(idx, self.clip_rect, shape)
} }
} }
@ -143,7 +143,7 @@ impl Painter {
let galley = font.layout_multiline(format!("🔥 {}", text), f32::INFINITY); let galley = font.layout_multiline(format!("🔥 {}", text), f32::INFINITY);
let rect = Align2::LEFT_TOP.anchor_rect(Rect::from_min_size(pos, galley.size)); let rect = Align2::LEFT_TOP.anchor_rect(Rect::from_min_size(pos, galley.size));
let frame_rect = rect.expand(2.0); let frame_rect = rect.expand(2.0);
self.add(PaintCmd::Rect { self.add(Shape::Rect {
rect: frame_rect, rect: frame_rect,
corner_radius: 0.0, corner_radius: 0.0,
fill: Color32::from_black_alpha(240), fill: Color32::from_black_alpha(240),
@ -157,7 +157,7 @@ impl Painter {
/// # Paint different primitives /// # Paint different primitives
impl Painter { impl Painter {
pub fn line_segment(&self, points: [Pos2; 2], stroke: impl Into<Stroke>) { pub fn line_segment(&self, points: [Pos2; 2], stroke: impl Into<Stroke>) {
self.add(PaintCmd::LineSegment { self.add(Shape::LineSegment {
points, points,
stroke: stroke.into(), stroke: stroke.into(),
}); });
@ -170,7 +170,7 @@ impl Painter {
fill_color: impl Into<Color32>, fill_color: impl Into<Color32>,
stroke: impl Into<Stroke>, stroke: impl Into<Stroke>,
) { ) {
self.add(PaintCmd::Circle { self.add(Shape::Circle {
center, center,
radius, radius,
fill: fill_color.into(), fill: fill_color.into(),
@ -179,7 +179,7 @@ impl Painter {
} }
pub fn circle_filled(&self, center: Pos2, radius: f32, fill_color: impl Into<Color32>) { pub fn circle_filled(&self, center: Pos2, radius: f32, fill_color: impl Into<Color32>) {
self.add(PaintCmd::Circle { self.add(Shape::Circle {
center, center,
radius, radius,
fill: fill_color.into(), fill: fill_color.into(),
@ -188,7 +188,7 @@ impl Painter {
} }
pub fn circle_stroke(&self, center: Pos2, radius: f32, stroke: impl Into<Stroke>) { pub fn circle_stroke(&self, center: Pos2, radius: f32, stroke: impl Into<Stroke>) {
self.add(PaintCmd::Circle { self.add(Shape::Circle {
center, center,
radius, radius,
fill: Default::default(), fill: Default::default(),
@ -203,7 +203,7 @@ impl Painter {
fill_color: impl Into<Color32>, fill_color: impl Into<Color32>,
stroke: impl Into<Stroke>, stroke: impl Into<Stroke>,
) { ) {
self.add(PaintCmd::Rect { self.add(Shape::Rect {
rect, rect,
corner_radius, corner_radius,
fill: fill_color.into(), fill: fill_color.into(),
@ -212,7 +212,7 @@ impl Painter {
} }
pub fn rect_filled(&self, rect: Rect, corner_radius: f32, fill_color: impl Into<Color32>) { pub fn rect_filled(&self, rect: Rect, corner_radius: f32, fill_color: impl Into<Color32>) {
self.add(PaintCmd::Rect { self.add(Shape::Rect {
rect, rect,
corner_radius, corner_radius,
fill: fill_color.into(), fill: fill_color.into(),
@ -221,7 +221,7 @@ impl Painter {
} }
pub fn rect_stroke(&self, rect: Rect, corner_radius: f32, stroke: impl Into<Stroke>) { pub fn rect_stroke(&self, rect: Rect, corner_radius: f32, stroke: impl Into<Stroke>) {
self.add(PaintCmd::Rect { self.add(Shape::Rect {
rect, rect,
corner_radius, corner_radius,
fill: Default::default(), fill: Default::default(),
@ -266,7 +266,7 @@ impl Painter {
/// Paint text that has already been layed out in a `Galley`. /// Paint text that has already been layed out in a `Galley`.
pub fn galley(&self, pos: Pos2, galley: Galley, text_style: TextStyle, color: Color32) { pub fn galley(&self, pos: Pos2, galley: Galley, text_style: TextStyle, color: Color32) {
self.add(PaintCmd::Text { self.add(Shape::Text {
pos, pos,
galley, galley,
text_style, text_style,

View file

@ -923,7 +923,7 @@ impl Ui {
(ret, response) (ret, response)
} }
/// Redirect paint commands to another paint layer. /// Redirect shapes to another paint layer.
pub fn with_layer_id<R>( pub fn with_layer_id<R>(
&mut self, &mut self,
layer_id: LayerId, layer_id: LayerId,

View file

@ -196,7 +196,7 @@ impl<'a> Widget for Checkbox<'a> {
rect.center().y - 0.5 * galley.size.y, rect.center().y - 0.5 * galley.size.y,
); );
let (small_icon_rect, big_icon_rect) = ui.style().spacing.icon_rectangles(rect); let (small_icon_rect, big_icon_rect) = ui.style().spacing.icon_rectangles(rect);
ui.painter().add(PaintCmd::Rect { ui.painter().add(Shape::Rect {
rect: big_icon_rect, rect: big_icon_rect,
corner_radius: visuals.corner_radius, corner_radius: visuals.corner_radius,
fill: visuals.bg_fill, fill: visuals.bg_fill,
@ -205,7 +205,7 @@ impl<'a> Widget for Checkbox<'a> {
if *checked { if *checked {
// Check mark: // Check mark:
ui.painter().add(PaintCmd::line( ui.painter().add(Shape::line(
vec![ vec![
pos2(small_icon_rect.left(), small_icon_rect.center().y), pos2(small_icon_rect.left(), small_icon_rect.center().y),
pos2(small_icon_rect.center().x, small_icon_rect.bottom()), pos2(small_icon_rect.center().x, small_icon_rect.bottom()),
@ -289,7 +289,7 @@ impl Widget for RadioButton {
let painter = ui.painter(); let painter = ui.painter();
painter.add(PaintCmd::Circle { painter.add(Shape::Circle {
center: big_icon_rect.center(), center: big_icon_rect.center(),
radius: big_icon_rect.width() / 2.0, radius: big_icon_rect.width() / 2.0,
fill: visuals.bg_fill, fill: visuals.bg_fill,
@ -297,7 +297,7 @@ impl Widget for RadioButton {
}); });
if checked { if checked {
painter.add(PaintCmd::Circle { painter.add(Shape::Circle {
center: small_icon_rect.center(), center: small_icon_rect.center(),
radius: small_icon_rect.width() / 3.0, radius: small_icon_rect.width() / 3.0,
fill: visuals.fg_stroke.color, // Intentional to use stroke and not fill fill: visuals.fg_stroke.color, // Intentional to use stroke and not fill

View file

@ -37,7 +37,7 @@ fn background_checkers(painter: &Painter, rect: Rect) {
); );
std::mem::swap(&mut top_color, &mut bottom_color); std::mem::swap(&mut top_color, &mut bottom_color);
} }
painter.add(PaintCmd::triangles(triangles)); painter.add(Shape::triangles(triangles));
} }
pub fn show_color(ui: &mut Ui, color: impl Into<Color32>, desired_size: Vec2) -> Response { pub fn show_color(ui: &mut Ui, color: impl Into<Color32>, desired_size: Vec2) -> Response {
@ -47,7 +47,7 @@ pub fn show_color(ui: &mut Ui, color: impl Into<Color32>, desired_size: Vec2) ->
fn show_srgba(ui: &mut Ui, srgba: Color32, desired_size: Vec2) -> Response { fn show_srgba(ui: &mut Ui, srgba: Color32, desired_size: Vec2) -> Response {
let (rect, response) = ui.allocate_at_least(desired_size, Sense::hover()); let (rect, response) = ui.allocate_at_least(desired_size, Sense::hover());
background_checkers(ui.painter(), rect); background_checkers(ui.painter(), rect);
ui.painter().add(PaintCmd::Rect { ui.painter().add(Shape::Rect {
rect, rect,
corner_radius: 2.0, corner_radius: 2.0,
fill: srgba, fill: srgba,
@ -61,7 +61,7 @@ fn color_button(ui: &mut Ui, color: Color32) -> Response {
let (rect, response) = ui.allocate_at_least(desired_size, Sense::click()); let (rect, response) = ui.allocate_at_least(desired_size, Sense::click());
let visuals = ui.style().interact(&response); let visuals = ui.style().interact(&response);
background_checkers(ui.painter(), rect); background_checkers(ui.painter(), rect);
ui.painter().add(PaintCmd::Rect { ui.painter().add(Shape::Rect {
rect, rect,
corner_radius: visuals.corner_radius.at_most(2.0), corner_radius: visuals.corner_radius.at_most(2.0),
fill: color, fill: color,
@ -103,7 +103,7 @@ fn color_slider_1d(ui: &mut Ui, value: &mut f32, color_at: impl Fn(f32) -> Color
triangles.add_triangle(2 * i + 1, 2 * i + 2, 2 * i + 3); triangles.add_triangle(2 * i + 1, 2 * i + 2, 2 * i + 3);
} }
} }
ui.painter().add(PaintCmd::triangles(triangles)); ui.painter().add(Shape::triangles(triangles));
} }
ui.painter().rect_stroke(rect, 0.0, visuals.bg_stroke); // outline ui.painter().rect_stroke(rect, 0.0, visuals.bg_stroke); // outline
@ -113,7 +113,7 @@ fn color_slider_1d(ui: &mut Ui, value: &mut f32, color_at: impl Fn(f32) -> Color
let x = lerp(rect.left()..=rect.right(), *value); let x = lerp(rect.left()..=rect.right(), *value);
let r = rect.height() / 4.0; let r = rect.height() / 4.0;
let picked_color = color_at(*value); let picked_color = color_at(*value);
ui.painter().add(PaintCmd::polygon( ui.painter().add(Shape::polygon(
vec![ vec![
pos2(x - r, rect.bottom()), pos2(x - r, rect.bottom()),
pos2(x + r, rect.bottom()), pos2(x + r, rect.bottom()),
@ -164,7 +164,7 @@ fn color_slider_2d(
} }
} }
} }
ui.painter().add(PaintCmd::triangles(triangles)); // fill ui.painter().add(Shape::triangles(triangles)); // fill
ui.painter().rect_stroke(rect, 0.0, visuals.bg_stroke); // outline ui.painter().rect_stroke(rect, 0.0, visuals.bg_stroke); // outline
@ -172,7 +172,7 @@ fn color_slider_2d(
let x = lerp(rect.left()..=rect.right(), *x_value); let x = lerp(rect.left()..=rect.right(), *x_value);
let y = lerp(rect.bottom()..=rect.top(), *y_value); let y = lerp(rect.bottom()..=rect.top(), *y_value);
let picked_color = color_at(*x_value, *y_value); let picked_color = color_at(*x_value, *y_value);
ui.painter().add(PaintCmd::Circle { ui.painter().add(Shape::Circle {
center: pos2(x, y), center: pos2(x, y),
radius: rect.width() / 12.0, radius: rect.width() / 12.0,
fill: picked_color, fill: picked_color,

View file

@ -59,14 +59,14 @@ impl Image {
if *bg_fill != Default::default() { if *bg_fill != Default::default() {
let mut triangles = Triangles::default(); let mut triangles = Triangles::default();
triangles.add_colored_rect(rect, *bg_fill); triangles.add_colored_rect(rect, *bg_fill);
ui.painter().add(PaintCmd::triangles(triangles)); ui.painter().add(Shape::triangles(triangles));
} }
{ {
// TODO: builder pattern for Triangles // TODO: builder pattern for Triangles
let mut triangles = Triangles::with_texture(*texture_id); let mut triangles = Triangles::with_texture(*texture_id);
triangles.add_rect_with_uv(rect, *uv, *tint); triangles.add_rect_with_uv(rect, *uv, *tint);
ui.painter().add(PaintCmd::triangles(triangles)); ui.painter().add(Shape::triangles(triangles));
} }
} }
} }

View file

@ -277,14 +277,14 @@ impl<'a> Slider<'a> {
); );
let marker_center_x = self.x_from_value(value, x_range); let marker_center_x = self.x_from_value(value, x_range);
ui.painter().add(PaintCmd::Rect { ui.painter().add(Shape::Rect {
rect: rail_rect, rect: rail_rect,
corner_radius: rail_radius, corner_radius: rail_radius,
fill: ui.style().visuals.widgets.inactive.bg_fill, fill: ui.style().visuals.widgets.inactive.bg_fill,
stroke: ui.style().visuals.widgets.inactive.bg_stroke, stroke: ui.style().visuals.widgets.inactive.bg_stroke,
}); });
ui.painter().add(PaintCmd::Circle { ui.painter().add(Shape::Circle {
center: pos2(marker_center_x, rail_rect.center().y), center: pos2(marker_center_x, rail_rect.center().y),
radius: handle_radius(rect), radius: handle_radius(rect),
fill: ui.style().interact(response).fg_fill, fill: ui.style().interact(response).fg_fill,

View file

@ -216,7 +216,7 @@ impl<'t> Widget for TextEdit<'t> {
let margin = Vec2::splat(2.0); let margin = Vec2::splat(2.0);
let frame_rect = ui.available_rect_before_wrap(); let frame_rect = ui.available_rect_before_wrap();
let content_rect = frame_rect.shrink2(margin); let content_rect = frame_rect.shrink2(margin);
let where_to_put_background = ui.painter().add(PaintCmd::Noop); let where_to_put_background = ui.painter().add(Shape::Noop);
let mut content_ui = ui.child_ui(content_rect, *ui.layout()); let mut content_ui = ui.child_ui(content_rect, *ui.layout());
let response = self.content_ui(&mut content_ui); let response = self.content_ui(&mut content_ui);
let frame_rect = Rect::from_min_max(frame_rect.min, content_ui.min_rect().max + margin); let frame_rect = Rect::from_min_max(frame_rect.min, content_ui.min_rect().max + margin);
@ -226,7 +226,7 @@ impl<'t> Widget for TextEdit<'t> {
let frame_rect = response.rect; let frame_rect = response.rect;
ui.painter().set( ui.painter().set(
where_to_put_background, where_to_put_background,
PaintCmd::Rect { Shape::Rect {
rect: frame_rect, rect: frame_rect,
corner_radius: visuals.corner_radius, corner_radius: visuals.corner_radius,
fill: ui.style().visuals.dark_bg_color, fill: ui.style().visuals.dark_bg_color,

View file

@ -36,11 +36,9 @@ pub fn criterion_benchmark(c: &mut Criterion) {
let mut demo_windows = egui_demo_lib::DemoWindows::default(); let mut demo_windows = egui_demo_lib::DemoWindows::default();
ctx.begin_frame(raw_input.clone()); ctx.begin_frame(raw_input.clone());
demo_windows.ui(&ctx); demo_windows.ui(&ctx);
let (_, paint_commands) = ctx.end_frame(); let (_, shapes) = ctx.end_frame();
c.bench_function("tessellate", |b| { c.bench_function("tessellate", |b| b.iter(|| ctx.tessellate(shapes.clone())));
b.iter(|| ctx.tessellate(paint_commands.clone()))
});
} }
{ {

View file

@ -300,7 +300,7 @@ fn vertex_gradient(ui: &mut Ui, bg_fill: Color32, gradient: &Gradient) -> Respon
if bg_fill != Default::default() { if bg_fill != Default::default() {
let mut triangles = Triangles::default(); let mut triangles = Triangles::default();
triangles.add_colored_rect(rect, bg_fill); triangles.add_colored_rect(rect, bg_fill);
ui.painter().add(PaintCmd::triangles(triangles)); ui.painter().add(Shape::triangles(triangles));
} }
{ {
let n = gradient.0.len(); let n = gradient.0.len();
@ -317,7 +317,7 @@ fn vertex_gradient(ui: &mut Ui, bg_fill: Color32, gradient: &Gradient) -> Respon
triangles.add_triangle(2 * i + 1, 2 * i + 2, 2 * i + 3); triangles.add_triangle(2 * i + 1, 2 * i + 2, 2 * i + 3);
} }
} }
ui.painter().add(PaintCmd::triangles(triangles)); ui.painter().add(Shape::triangles(triangles));
} }
response response
} }

View file

@ -34,7 +34,7 @@ impl super::View for DancingStrings {
let desired_size = ui.available_width() * vec2(1.0, 0.35); let desired_size = ui.available_width() * vec2(1.0, 0.35);
let (_id, rect) = ui.allocate_space(desired_size); let (_id, rect) = ui.allocate_space(desired_size);
let mut cmds = vec![]; let mut shapes = vec![];
for &mode in &[2, 3, 5] { for &mode in &[2, 3, 5] {
let mode = mode as f32; let mode = mode as f32;
@ -55,13 +55,13 @@ impl super::View for DancingStrings {
.collect(); .collect();
let thickness = 10.0 / mode; let thickness = 10.0 / mode;
cmds.push(paint::PaintCmd::line( shapes.push(paint::Shape::line(
points, points,
Stroke::new(thickness, Color32::from_additive_luminance(196)), Stroke::new(thickness, Color32::from_additive_luminance(196)),
)); ));
} }
ui.painter().extend(cmds); ui.painter().extend(shapes);
}); });
ui.add(crate::__egui_github_link_file!()); ui.add(crate::__egui_github_link_file!());
} }

View file

@ -43,7 +43,7 @@ pub fn drop_target<R>(
let outer_rect_bounds = ui.available_rect_before_wrap(); let outer_rect_bounds = ui.available_rect_before_wrap();
let inner_rect = outer_rect_bounds.shrink2(margin); let inner_rect = outer_rect_bounds.shrink2(margin);
let where_to_put_background = ui.painter().add(PaintCmd::Noop); let where_to_put_background = ui.painter().add(Shape::Noop);
let mut content_ui = ui.child_ui(inner_rect, *ui.layout()); let mut content_ui = ui.child_ui(inner_rect, *ui.layout());
let ret = body(&mut content_ui); let ret = body(&mut content_ui);
let outer_rect = Rect::from_min_max(outer_rect_bounds.min, content_ui.min_rect().max + margin); let outer_rect = Rect::from_min_max(outer_rect_bounds.min, content_ui.min_rect().max + margin);
@ -61,7 +61,7 @@ pub fn drop_target<R>(
ui.painter().set( ui.painter().set(
where_to_put_background, where_to_put_background,
PaintCmd::Rect { Shape::Rect {
corner_radius: style.corner_radius, corner_radius: style.corner_radius,
fill: style.bg_fill, fill: style.bg_fill,
stroke: style.bg_stroke, stroke: style.bg_stroke,

View file

@ -52,7 +52,7 @@ impl Painting {
for line in &self.lines { for line in &self.lines {
if line.len() >= 2 { if line.len() >= 2 {
let points: Vec<Pos2> = line.iter().map(|p| rect.min + *p).collect(); let points: Vec<Pos2> = line.iter().map(|p| rect.min + *p).collect();
painter.add(PaintCmd::line(points, self.stroke)); painter.add(Shape::line(points, self.stroke));
} }
} }
} }

View file

@ -69,7 +69,7 @@ impl FrameHistory {
let (rect, response) = ui.allocate_at_least(size, Sense::hover()); let (rect, response) = ui.allocate_at_least(size, Sense::hover());
let style = ui.style().noninteractive(); let style = ui.style().noninteractive();
let mut cmds = vec![PaintCmd::Rect { let mut shapes = vec![Shape::Rect {
rect, rect,
corner_radius: style.corner_radius, corner_radius: style.corner_radius,
fill: ui.style().visuals.dark_bg_color, fill: ui.style().visuals.dark_bg_color,
@ -82,13 +82,13 @@ impl FrameHistory {
if let Some(mouse_pos) = ui.input().mouse.pos { if let Some(mouse_pos) = ui.input().mouse.pos {
if rect.contains(mouse_pos) { if rect.contains(mouse_pos) {
let y = mouse_pos.y; let y = mouse_pos.y;
cmds.push(PaintCmd::line_segment( shapes.push(Shape::line_segment(
[pos2(rect.left(), y), pos2(rect.right(), y)], [pos2(rect.left(), y), pos2(rect.right(), y)],
line_stroke, line_stroke,
)); ));
let cpu_usage = remap(y, rect.bottom_up_range(), 0.0..=graph_top_cpu_usage); let cpu_usage = remap(y, rect.bottom_up_range(), 0.0..=graph_top_cpu_usage);
let text = format!("{:.1} ms", 1e3 * cpu_usage); let text = format!("{:.1} ms", 1e3 * cpu_usage);
cmds.push(PaintCmd::text( shapes.push(Shape::text(
ui.fonts(), ui.fonts(),
pos2(rect.left(), y), pos2(rect.left(), y),
egui::Align2::LEFT_BOTTOM, egui::Align2::LEFT_BOTTOM,
@ -108,17 +108,17 @@ impl FrameHistory {
let x = remap(age, history.max_age()..=0.0, rect.x_range()); let x = remap(age, history.max_age()..=0.0, rect.x_range());
let y = remap_clamp(cpu_usage, 0.0..=graph_top_cpu_usage, rect.bottom_up_range()); let y = remap_clamp(cpu_usage, 0.0..=graph_top_cpu_usage, rect.bottom_up_range());
cmds.push(PaintCmd::line_segment( shapes.push(Shape::line_segment(
[pos2(x, rect.bottom()), pos2(x, y)], [pos2(x, rect.bottom()), pos2(x, y)],
line_stroke, line_stroke,
)); ));
if cpu_usage < graph_top_cpu_usage { if cpu_usage < graph_top_cpu_usage {
cmds.push(PaintCmd::circle_filled(pos2(x, y), radius, circle_color)); shapes.push(Shape::circle_filled(pos2(x, y), radius, circle_color));
} }
} }
ui.painter().extend(cmds); ui.painter().extend(shapes);
response response
} }

View file

@ -98,8 +98,8 @@ fn test_egui_e2e() {
for _ in 0..NUM_FRAMES { for _ in 0..NUM_FRAMES {
ctx.begin_frame(raw_input.clone()); ctx.begin_frame(raw_input.clone());
demo_windows.ui(&ctx); demo_windows.ui(&ctx);
let (_output, paint_commands) = ctx.end_frame(); let (_output, shapes) = ctx.end_frame();
let paint_jobs = ctx.tessellate(paint_commands); let paint_jobs = ctx.tessellate(shapes);
assert!(!paint_jobs.is_empty()); assert!(!paint_jobs.is_empty());
} }
} }

View file

@ -184,7 +184,7 @@ pub fn run(mut app: Box<dyn epi::App>) -> ! {
*ctx.memory() = saved_memory; // We don't want to remember that windows were huge. *ctx.memory() = saved_memory; // We don't want to remember that windows were huge.
ctx.clear_animations(); ctx.clear_animations();
let (egui_output, _paint_commands) = ctx.end_frame(); let (egui_output, _shapes) = ctx.end_frame();
handle_output(egui_output, &display, clipboard.as_mut()); handle_output(egui_output, &display, clipboard.as_mut());
// TODO: handle app_output // TODO: handle app_output
// eprintln!("Warmed up in {} ms", warm_up_start.elapsed().as_millis()) // eprintln!("Warmed up in {} ms", warm_up_start.elapsed().as_millis())
@ -211,8 +211,8 @@ pub fn run(mut app: Box<dyn epi::App>) -> ! {
} }
.build(); .build();
app.update(&ctx, &mut frame); app.update(&ctx, &mut frame);
let (egui_output, paint_commands) = ctx.end_frame(); let (egui_output, shapes) = ctx.end_frame();
let paint_jobs = ctx.tessellate(paint_commands); let paint_jobs = ctx.tessellate(shapes);
let frame_time = (Instant::now() - frame_start).as_secs_f64() as f32; let frame_time = (Instant::now() - frame_start).as_secs_f64() as f32;
previous_frame_time = Some(frame_time); previous_frame_time = Some(frame_time);

View file

@ -38,8 +38,8 @@ impl WebBackend {
.take() .take()
.expect("unmatched calls to begin_frame/end_frame"); .expect("unmatched calls to begin_frame/end_frame");
let (output, paint_commands) = self.ctx.end_frame(); let (output, shapes) = self.ctx.end_frame();
let paint_jobs = self.ctx.tessellate(paint_commands); let paint_jobs = self.ctx.tessellate(shapes);
let now = now_sec(); let now = now_sec();
self.previous_frame_time = Some((now - frame_start) as f32); self.previous_frame_time = Some((now - frame_start) as f32);

View file

@ -67,7 +67,7 @@ pub trait App {
/// If `true` a warm-up call to [`Self::update`] will be issued where /// If `true` a warm-up call to [`Self::update`] will be issued where
/// `ctx.memory().everything_is_visible()` will be set to `true`. /// `ctx.memory().everything_is_visible()` will be set to `true`.
/// ///
/// In this warm-up call, all paint commands will be ignored. /// In this warm-up call, all painted shapes will be ignored.
fn warm_up_enabled(&self) -> bool { fn warm_up_enabled(&self) -> bool {
false false
} }