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

Partial font texture update #1149

Merged
merged 5 commits into from
Jan 22, 2022
Merged
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
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w
* `Context` can now be cloned and stored between frames ([#1050](https://github.com/emilk/egui/pull/1050)).
* Renamed `Ui::visible` to `Ui::is_visible`.
* Split `Event::Text` into `Event::Text` and `Event::Paste` ([#1058](https://github.com/emilk/egui/pull/1058)).
* For integrations: `FontImage` has been replaced by `TexturesDelta` (found in `Output`), describing what textures were loaded and freed each frame ([#1110](https://github.com/emilk/egui/pull/1110)).
* For integrations:
* `FontImage` has been replaced by `TexturesDelta` (found in `Output`), describing what textures were loaded and freed each frame ([#1110](https://github.com/emilk/egui/pull/1110)).
* The painter must support partial texture updates ([#1149](https://github.com/emilk/egui/pull/1149)).

### Fixed 🐛
* Context menu now respects the theme ([#1043](https://github.com/emilk/egui/pull/1043))
Expand Down
17 changes: 7 additions & 10 deletions egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ struct ContextImpl {
fonts: Option<Fonts>,
memory: Memory,
animation_manager: AnimationManager,
latest_font_image_version: Option<u64>,
tex_manager: WrappedTextureManager,

input: InputState,
Expand Down Expand Up @@ -709,17 +708,15 @@ impl Context {
.memory
.end_frame(&ctx_impl.input, &ctx_impl.frame_state.used_ids);

let font_image = ctx_impl.fonts.as_ref().unwrap().font_image();
let font_image_version = font_image.version;

if Some(font_image_version) != ctx_impl.latest_font_image_version {
let font_image_delta = ctx_impl.fonts.as_ref().unwrap().font_image_delta();
if let Some(font_image_delta) = font_image_delta {
ctx_impl
.tex_manager
.0
.write()
.set(TextureId::default(), font_image.image.clone().into());
ctx_impl.latest_font_image_version = Some(font_image_version);
.set(TextureId::default(), font_image_delta);
}

ctx_impl
.output
.textures_delta
Expand Down Expand Up @@ -757,7 +754,7 @@ impl Context {
let clipped_meshes = tessellator::tessellate_shapes(
shapes,
tessellation_options,
self.fonts().font_image().size(),
self.fonts().font_image_size(),
);
self.write().paint_stats = paint_stats.with_clipped_meshes(&clipped_meshes);
clipped_meshes
Expand Down Expand Up @@ -961,8 +958,8 @@ impl Context {
.show(ui, |ui| {
let mut font_definitions = self.fonts().definitions().clone();
font_definitions.ui(ui);
let font_image = self.fonts().font_image();
font_image.ui(ui);
let font_image_size = self.fonts().font_image_size();
crate::introspection::font_texture_ui(ui, font_image_size);
self.set_fonts(font_definitions);
});

Expand Down
106 changes: 52 additions & 54 deletions egui/src/introspection.rs
Original file line number Diff line number Diff line change
@@ -1,60 +1,58 @@
//! uis for egui types.
use crate::*;

impl Widget for &epaint::FontImage {
fn ui(self, ui: &mut Ui) -> Response {
use epaint::Mesh;

ui.vertical(|ui| {
// Show font texture in demo Ui
let [width, height] = self.size();

ui.label(format!(
"Texture size: {} x {} (hover to zoom)",
width, height
));
if width <= 1 || height <= 1 {
return;
}
let mut size = vec2(width as f32, height as f32);
if size.x > ui.available_width() {
size *= ui.available_width() / size.x;
}
let (rect, response) = ui.allocate_at_least(size, Sense::hover());
let mut mesh = Mesh::default();
mesh.add_rect_with_uv(
rect,
[pos2(0.0, 0.0), pos2(1.0, 1.0)].into(),
Color32::WHITE,
);
ui.painter().add(Shape::mesh(mesh));

let (tex_w, tex_h) = (width as f32, height as f32);

response
.on_hover_cursor(CursorIcon::ZoomIn)
.on_hover_ui_at_pointer(|ui| {
if let Some(pos) = ui.ctx().latest_pointer_pos() {
let (_id, zoom_rect) = ui.allocate_space(vec2(128.0, 128.0));
let u = remap_clamp(pos.x, rect.x_range(), 0.0..=tex_w);
let v = remap_clamp(pos.y, rect.y_range(), 0.0..=tex_h);

let texel_radius = 32.0;
let u = u.at_least(texel_radius).at_most(tex_w - texel_radius);
let v = v.at_least(texel_radius).at_most(tex_h - texel_radius);

let uv_rect = Rect::from_min_max(
pos2((u - texel_radius) / tex_w, (v - texel_radius) / tex_h),
pos2((u + texel_radius) / tex_w, (v + texel_radius) / tex_h),
);
let mut mesh = Mesh::default();
mesh.add_rect_with_uv(zoom_rect, uv_rect, Color32::WHITE);
ui.painter().add(Shape::mesh(mesh));
}
});
})
.response
}
// Show font texture in demo Ui
pub(crate) fn font_texture_ui(ui: &mut Ui, [width, height]: [usize; 2]) -> Response {
use epaint::Mesh;

ui.vertical(|ui| {
let color = if ui.visuals().dark_mode {
Color32::WHITE
} else {
Color32::BLACK
};

ui.label(format!(
"Texture size: {} x {} (hover to zoom)",
width, height
));
if width <= 1 || height <= 1 {
return;
}
let mut size = vec2(width as f32, height as f32);
if size.x > ui.available_width() {
size *= ui.available_width() / size.x;
}
let (rect, response) = ui.allocate_at_least(size, Sense::hover());
let mut mesh = Mesh::default();
mesh.add_rect_with_uv(rect, [pos2(0.0, 0.0), pos2(1.0, 1.0)].into(), color);
ui.painter().add(Shape::mesh(mesh));

let (tex_w, tex_h) = (width as f32, height as f32);

response
.on_hover_cursor(CursorIcon::ZoomIn)
.on_hover_ui_at_pointer(|ui| {
if let Some(pos) = ui.ctx().latest_pointer_pos() {
let (_id, zoom_rect) = ui.allocate_space(vec2(128.0, 128.0));
let u = remap_clamp(pos.x, rect.x_range(), 0.0..=tex_w);
let v = remap_clamp(pos.y, rect.y_range(), 0.0..=tex_h);

let texel_radius = 32.0;
let u = u.at_least(texel_radius).at_most(tex_w - texel_radius);
let v = v.at_least(texel_radius).at_most(tex_h - texel_radius);

let uv_rect = Rect::from_min_max(
pos2((u - texel_radius) / tex_w, (v - texel_radius) / tex_h),
pos2((u + texel_radius) / tex_w, (v + texel_radius) / tex_h),
);
let mut mesh = Mesh::default();
mesh.add_rect_with_uv(zoom_rect, uv_rect, color);
ui.painter().add(Shape::mesh(mesh));
}
});
})
.response
}

impl Widget for &mut epaint::text::FontDefinitions {
Expand Down
8 changes: 6 additions & 2 deletions egui/src/widgets/plot/items/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1087,9 +1087,13 @@ pub struct PlotImage {

impl PlotImage {
/// Create a new image with position and size in plot coordinates.
pub fn new(texture_id: impl Into<TextureId>, position: Value, size: impl Into<Vec2>) -> Self {
pub fn new(
texture_id: impl Into<TextureId>,
center_position: Value,
size: impl Into<Vec2>,
) -> Self {
Self {
position,
position: center_position,
name: Default::default(),
highlight: false,
texture_id: texture_id.into(),
Expand Down
6 changes: 1 addition & 5 deletions egui_demo_lib/benches/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
let text_shape = TextShape::new(egui::Pos2::ZERO, galley);
c.bench_function("tessellate_text", |b| {
b.iter(|| {
tessellator.tessellate_text(
fonts.font_image().size(),
text_shape.clone(),
&mut mesh,
);
tessellator.tessellate_text(fonts.font_image_size(), text_shape.clone(), &mut mesh);
mesh.clear();
})
});
Expand Down
5 changes: 1 addition & 4 deletions egui_demo_lib/src/apps/demo/plot_demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,10 +343,7 @@ impl Widget for &mut ItemsDemo {
let image = PlotImage::new(
texture,
Value::new(0.0, 10.0),
[
ui.fonts().font_image().width() as f32 / 100.0,
ui.fonts().font_image().height() as f32 / 100.0,
],
5.0 * vec2(texture.aspect_ratio(), 1.0),
);

let plot = Plot::new("items_demo")
Expand Down
4 changes: 2 additions & 2 deletions egui_glium/src/epi_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ pub fn run(app: Box<dyn epi::App>, native_options: &epi::NativeOptions) -> ! {
integration.update(display.gl_window().window());
let clipped_meshes = integration.egui_ctx.tessellate(shapes);

for (id, image) in textures_delta.set {
painter.set_texture(&display, id, &image);
for (id, image_delta) in textures_delta.set {
painter.set_texture(&display, id, &image_delta);
}

// paint:
Expand Down
4 changes: 2 additions & 2 deletions egui_glium/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ impl EguiGlium {
let shapes = std::mem::take(&mut self.shapes);
let mut textures_delta = std::mem::take(&mut self.textures_delta);

for (id, image) in textures_delta.set {
self.painter.set_texture(display, id, &image);
for (id, image_delta) in textures_delta.set {
self.painter.set_texture(display, id, &image_delta);
}

let clipped_meshes = self.egui_ctx.tessellate(shapes);
Expand Down
26 changes: 20 additions & 6 deletions egui_glium/src/painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,9 @@ impl Painter {
&mut self,
facade: &dyn glium::backend::Facade,
tex_id: egui::TextureId,
image: &egui::ImageData,
delta: &egui::epaint::ImageDelta,
) {
let pixels: Vec<(u8, u8, u8, u8)> = match image {
let pixels: Vec<(u8, u8, u8, u8)> = match &delta.image {
egui::ImageData::Color(image) => {
assert_eq!(
image.width() * image.height(),
Expand All @@ -206,15 +206,29 @@ impl Painter {
};
let glium_image = glium::texture::RawImage2d {
data: std::borrow::Cow::Owned(pixels),
width: image.width() as _,
height: image.height() as _,
width: delta.image.width() as _,
height: delta.image.height() as _,
format: glium::texture::ClientFormat::U8U8U8U8,
};
let format = texture::SrgbFormat::U8U8U8U8;
let mipmaps = texture::MipmapsOption::NoMipmap;
let gl_texture = SrgbTexture2d::with_format(facade, glium_image, format, mipmaps).unwrap();

self.textures.insert(tex_id, gl_texture.into());
if let Some(pos) = delta.pos {
// update a sub-region
if let Some(gl_texture) = self.textures.get(&tex_id) {
let rect = glium::Rect {
left: pos[0] as _,
bottom: pos[1] as _,
width: glium_image.width,
height: glium_image.height,
};
gl_texture.main_level().write(rect, glium_image);
}
} else {
let gl_texture =
SrgbTexture2d::with_format(facade, glium_image, format, mipmaps).unwrap();
self.textures.insert(tex_id, gl_texture.into());
}
}

pub fn free_texture(&mut self, tex_id: egui::TextureId) {
Expand Down
4 changes: 2 additions & 2 deletions egui_glow/src/epi_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ pub fn run(app: Box<dyn epi::App>, native_options: &epi::NativeOptions) -> ! {
integration.update(gl_window.window());
let clipped_meshes = integration.egui_ctx.tessellate(shapes);

for (id, image) in textures_delta.set {
painter.set_texture(&gl, id, &image);
for (id, image_delta) in textures_delta.set {
painter.set_texture(&gl, id, &image_delta);
}

// paint:
Expand Down
4 changes: 2 additions & 2 deletions egui_glow/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ impl EguiGlow {
let shapes = std::mem::take(&mut self.shapes);
let mut textures_delta = std::mem::take(&mut self.textures_delta);

for (id, image) in textures_delta.set {
self.painter.set_texture(gl, id, &image);
for (id, image_delta) in textures_delta.set {
self.painter.set_texture(gl, id, &image_delta);
}

let clipped_meshes = self.egui_ctx.tessellate(shapes);
Expand Down
Loading