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

Allow specification of a TextureFilter per texture #1296

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 4 additions & 2 deletions egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ impl Default for WrappedTextureManager {
let font_id = tex_mngr.alloc(
"egui_font_texture".into(),
epaint::AlphaImage::new([0, 0]).into(),
epaint::TextureFilter::Linear,
);
assert_eq!(font_id, TextureId::default());

Expand Down Expand Up @@ -652,7 +653,7 @@ impl Context {
/// fn ui(&mut self, ui: &mut egui::Ui) {
/// let texture: &egui::TextureHandle = self.texture.get_or_insert_with(|| {
/// // Load the texture only once.
/// ui.ctx().load_texture("my-image", egui::ColorImage::example())
/// ui.ctx().load_texture("my-image", egui::ColorImage::example(), Default::default())
/// });
///
/// // Show the image:
Expand All @@ -666,9 +667,10 @@ impl Context {
&self,
name: impl Into<String>,
image: impl Into<ImageData>,
filter: TextureFilter,
) -> TextureHandle {
let tex_mngr = self.tex_manager();
let tex_id = tex_mngr.write().alloc(name.into(), image.into());
let tex_id = tex_mngr.write().alloc(name.into(), image.into(), filter);
TextureHandle::new(tex_mngr, tex_id)
}

Expand Down
4 changes: 2 additions & 2 deletions egui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,9 +385,9 @@ pub use emath::{lerp, pos2, remap, remap_clamp, vec2, Align, Align2, NumExt, Pos
pub use epaint::{
color, mutex,
text::{FontData, FontDefinitions, FontFamily, FontId, FontTweak},
textures::TexturesDelta,
textures::{TextureDelta, TexturesDelta},
AlphaImage, ClippedMesh, Color32, ColorImage, ImageData, Mesh, Rgba, Rounding, Shape, Stroke,
TextureHandle, TextureId,
TextureFilter, TextureHandle, TextureId,
};

pub mod text {
Expand Down
2 changes: 1 addition & 1 deletion egui/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1426,7 +1426,7 @@ impl Ui {
/// fn ui(&mut self, ui: &mut egui::Ui) {
/// let texture: &egui::TextureHandle = self.texture.get_or_insert_with(|| {
/// // Load the texture only once.
/// ui.ctx().load_texture("my-image", egui::ColorImage::example())
/// ui.ctx().load_texture("my-image", egui::ColorImage::example(), Default::default())
/// });
///
/// // Show the image:
Expand Down
2 changes: 1 addition & 1 deletion egui/src/widgets/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::*;
/// fn ui(&mut self, ui: &mut egui::Ui) {
/// let texture: &egui::TextureHandle = self.texture.get_or_insert_with(|| {
/// // Load the texture only once.
/// ui.ctx().load_texture("my-image", egui::ColorImage::example())
/// ui.ctx().load_texture("my-image", egui::ColorImage::example(), Default::default())
/// });
///
/// // Show the image:
Expand Down
1 change: 1 addition & 0 deletions egui_demo_lib/src/apps/color_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ impl TextureManager {
size: [width, height],
pixels,
},
TextureFilter::default(),
)
})
}
Expand Down
7 changes: 5 additions & 2 deletions egui_demo_lib/src/apps/demo/plot_demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,8 +421,11 @@ impl Widget for &mut ItemsDemo {
};

let texture: &egui::TextureHandle = self.texture.get_or_insert_with(|| {
ui.ctx()
.load_texture("plot_demo", egui::ColorImage::example())
ui.ctx().load_texture(
"plot_demo",
egui::ColorImage::example(),
egui::TextureFilter::default(),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
egui::TextureFilter::default(),
Default::default(),

this is shorter and more future proof (i.e. will work even if we change the name/type of this argument)

)
});
let image = PlotImage::new(
texture,
Expand Down
7 changes: 5 additions & 2 deletions egui_demo_lib/src/apps/demo/widget_gallery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,11 @@ impl WidgetGallery {
} = self;

let texture: &egui::TextureHandle = texture.get_or_insert_with(|| {
ui.ctx()
.load_texture("example", egui::ColorImage::example())
ui.ctx().load_texture(
"example",
egui::ColorImage::example(),
egui::TextureFilter::default(),
)
});

ui.add(doc_link_label("Label", "label,heading"));
Expand Down
2 changes: 1 addition & 1 deletion egui_extras/src/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl RetainedImage {
.get_or_insert_with(|| {
let image: &mut ColorImage = &mut self.image.lock();
let image = std::mem::take(image);
ctx.load_texture(&self.debug_name, image)
ctx.load_texture(&self.debug_name, image, egui::TextureFilter::default())
})
.id()
}
Expand Down
46 changes: 30 additions & 16 deletions egui_glium/src/painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub struct Painter {
max_texture_side: usize,
program: glium::Program,

textures: AHashMap<egui::TextureId, Rc<SrgbTexture2d>>,
textures: AHashMap<egui::TextureId, (Rc<SrgbTexture2d>, egui::TextureFilter)>,

#[cfg(feature = "epi")]
/// [`egui::TextureId::User`] index
Expand Down Expand Up @@ -73,8 +73,8 @@ impl Painter {
clipped_meshes: Vec<egui::ClippedMesh>,
textures_delta: &egui::TexturesDelta,
) {
for (id, image_delta) in &textures_delta.set {
self.set_texture(display, *id, image_delta);
for (id, delta) in &textures_delta.set {
self.set_texture(display, *id, delta);
}

self.paint_meshes(display, target, pixels_per_point, clipped_meshes);
Expand Down Expand Up @@ -134,10 +134,13 @@ impl Painter {
let width_in_points = width_in_pixels as f32 / pixels_per_point;
let height_in_points = height_in_pixels as f32 / pixels_per_point;

if let Some(texture) = self.get_texture(mesh.texture_id) {
if let Some((texture, stored_filter)) = self.get_texture(mesh.texture_id) {
// The texture coordinates for text are so that both nearest and linear should work with the egui font texture.
// For user textures linear sampling is more likely to be the right choice.
let filter = MagnifySamplerFilter::Linear;
let filter = match stored_filter {
egui::TextureFilter::Linear => MagnifySamplerFilter::Linear,
egui::TextureFilter::Nearest => MagnifySamplerFilter::Nearest,
};

let uniforms = uniform! {
u_screen_size: [width_in_points, height_in_points],
Expand Down Expand Up @@ -213,9 +216,14 @@ impl Painter {
&mut self,
facade: &dyn glium::backend::Facade,
tex_id: egui::TextureId,
delta: &egui::epaint::ImageDelta,
delta: &egui::TextureDelta,
) {
let pixels: Vec<(u8, u8, u8, u8)> = match &delta.image {
let egui::TextureDelta {
image: image_delta,
filter,
} = delta;

let pixels: Vec<(u8, u8, u8, u8)> = match &image_delta.image {
egui::ImageData::Color(image) => {
assert_eq!(
image.width() * image.height(),
Expand All @@ -234,37 +242,43 @@ impl Painter {
};
let glium_image = glium::texture::RawImage2d {
data: std::borrow::Cow::Owned(pixels),
width: delta.image.width() as _,
height: delta.image.height() as _,
width: image_delta.image.width() as _,
height: image_delta.image.height() as _,
format: glium::texture::ClientFormat::U8U8U8U8,
};
let format = texture::SrgbFormat::U8U8U8U8;
let mipmaps = texture::MipmapsOption::NoMipmap;

if let Some(pos) = delta.pos {
if let Some(pos) = image_delta.pos {
// update a sub-region
if let Some(gl_texture) = self.textures.get(&tex_id) {
if let Some((gl_texture, stored_filter)) = self.textures.get_mut(&tex_id) {
let rect = glium::Rect {
left: pos[0] as _,
bottom: pos[1] as _,
width: glium_image.width,
height: glium_image.height,
};
*stored_filter = *filter;
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());
self.textures.insert(tex_id, (gl_texture.into(), *filter));
}
}

pub fn free_texture(&mut self, tex_id: egui::TextureId) {
self.textures.remove(&tex_id);
}

fn get_texture(&self, texture_id: egui::TextureId) -> Option<&SrgbTexture2d> {
self.textures.get(&texture_id).map(|rc| rc.as_ref())
fn get_texture(
&self,
texture_id: egui::TextureId,
) -> Option<(&SrgbTexture2d, egui::TextureFilter)> {
self.textures
.get(&texture_id)
.map(|(rc, filter)| (rc.as_ref(), *filter))
}
}

Expand All @@ -275,11 +289,11 @@ impl epi::NativeTexture for Painter {
fn register_native_texture(&mut self, native: Self::Texture) -> egui::TextureId {
let id = egui::TextureId::User(self.next_native_tex_id);
self.next_native_tex_id += 1;
self.textures.insert(id, native);
self.textures.insert(id, (native, Default::default()));
id
}

fn replace_native_texture(&mut self, id: egui::TextureId, replacing: Self::Texture) {
self.textures.insert(id, replacing);
self.textures.insert(id, (replacing, Default::default()));
}
}
56 changes: 18 additions & 38 deletions egui_glow/src/painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ pub struct Painter {
is_embedded: bool,
vertex_array: crate::misc_util::VAO,
srgb_support: bool,
/// The filter used for subsequent textures.
texture_filter: TextureFilter,
post_process: Option<PostProcess>,
vertex_buffer: glow::Buffer,
element_array_buffer: glow::Buffer,
Expand All @@ -51,27 +49,6 @@ pub struct Painter {
destroyed: bool,
}

#[derive(Copy, Clone)]
pub enum TextureFilter {
Linear,
Nearest,
}

impl Default for TextureFilter {
fn default() -> Self {
TextureFilter::Linear
}
}

impl TextureFilter {
pub(crate) fn glow_code(&self) -> u32 {
match self {
TextureFilter::Linear => glow::LINEAR,
TextureFilter::Nearest => glow::NEAREST,
}
}
}

impl Painter {
/// Create painter.
///
Expand Down Expand Up @@ -215,7 +192,6 @@ impl Painter {
is_embedded: matches!(shader_version, ShaderVersion::Es100 | ShaderVersion::Es300),
vertex_array,
srgb_support,
texture_filter: Default::default(),
post_process,
vertex_buffer,
element_array_buffer,
Expand Down Expand Up @@ -278,8 +254,8 @@ impl Painter {
clipped_meshes: Vec<egui::ClippedMesh>,
textures_delta: &egui::TexturesDelta,
) {
for (id, image_delta) in &textures_delta.set {
self.set_texture(gl, *id, image_delta);
for (id, delta) in &textures_delta.set {
self.set_texture(gl, *id, delta);
}

self.paint_meshes(gl, inner_size, pixels_per_point, clipped_meshes);
Expand Down Expand Up @@ -403,22 +379,21 @@ impl Painter {
}
}

// Set the filter to be used for any subsequent textures loaded via
// [`Self::set_texture`].
pub fn set_texture_filter(&mut self, texture_filter: TextureFilter) {
self.texture_filter = texture_filter;
}

// ------------------------------------------------------------------------

pub fn set_texture(
&mut self,
gl: &glow::Context,
tex_id: egui::TextureId,
delta: &egui::epaint::ImageDelta,
delta: &egui::TextureDelta,
) {
self.assert_not_destroyed();

let egui::TextureDelta {
filter,
image: image_delta,
} = delta;

let glow_texture = *self
.textures
.entry(tex_id)
Expand All @@ -427,7 +402,7 @@ impl Painter {
gl.bind_texture(glow::TEXTURE_2D, Some(glow_texture));
}

match &delta.image {
match &image_delta.image {
egui::ImageData::Color(image) => {
assert_eq!(
image.width() * image.height(),
Expand All @@ -437,7 +412,7 @@ impl Painter {

let data: &[u8] = bytemuck::cast_slice(image.pixels.as_ref());

self.upload_texture_srgb(gl, delta.pos, image.size, data);
self.upload_texture_srgb(gl, image_delta.pos, image.size, data, *filter);
}
egui::ImageData::Alpha(image) => {
assert_eq!(
Expand All @@ -456,7 +431,7 @@ impl Painter {
.flat_map(|a| a.to_array())
.collect();

self.upload_texture_srgb(gl, delta.pos, image.size, &data);
self.upload_texture_srgb(gl, image_delta.pos, image.size, &data, *filter);
}
};
}
Expand All @@ -467,19 +442,24 @@ impl Painter {
pos: Option<[usize; 2]>,
[w, h]: [usize; 2],
data: &[u8],
filter: egui::TextureFilter,
) {
let glow_filter = match filter {
egui::TextureFilter::Linear => glow::LINEAR,
egui::TextureFilter::Nearest => glow::NEAREST,
};
assert_eq!(data.len(), w * h * 4);
assert!(w >= 1 && h >= 1);
unsafe {
gl.tex_parameter_i32(
glow::TEXTURE_2D,
glow::TEXTURE_MAG_FILTER,
self.texture_filter.glow_code() as i32,
glow_filter as i32,
);
gl.tex_parameter_i32(
glow::TEXTURE_2D,
glow::TEXTURE_MIN_FILTER,
self.texture_filter.glow_code() as i32,
glow_filter as i32,
);

gl.tex_parameter_i32(
Expand Down
2 changes: 1 addition & 1 deletion egui_web/src/glow_wrapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl crate::Painter for WrappedGlowPainter {
self.painter.max_texture_side()
}

fn set_texture(&mut self, tex_id: egui::TextureId, delta: &egui::epaint::ImageDelta) {
fn set_texture(&mut self, tex_id: egui::TextureId, delta: &egui::TextureDelta) {
self.painter.set_texture(&self.glow_ctx, tex_id, delta);
}

Expand Down
4 changes: 2 additions & 2 deletions egui_web/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ mod painter;
pub mod screen_reader;
mod text_agent;

#[cfg(feature = "webgl")]
// #[cfg(feature = "webgl")]
pub mod webgl1;
#[cfg(feature = "webgl")]
// #[cfg(feature = "webgl")]
pub mod webgl2;

pub use backend::*;
Expand Down