Skip to content

Commit

Permalink
Add TextureOptions::wrap_mode (#3954)
Browse files Browse the repository at this point in the history
Exposes support in both glow and wgpu for texture wrap modes

This would be breaking for manual creations of TextureOptions but would
work with the current TextureOptions::NEAREST and LINEAR without change,
keeping those clamp to edge

I wasn't sure how best to expose the options to the user and added
consts for LINEAR_REPEAT LINEAR_MIRRORED_REPEAT NEAREST_REPEAT
NEAREST_MIRRORED_REPEAT

This does not include wrap mode clamp to border as it worked fine with
glow but with wgpu it panics due to Features
Features(ADDRESS_MODE_CLAMP_TO_BORDER) are required but not enabled on
the device, and I thought it was probably best not to try to enable that
feature, but happy to include that functionality also if that is okay to
be toggled


![image](https://github.com/emilk/egui/assets/5075747/bba71f61-a105-4e5b-b8ce-1083621eb3de)

---------

Co-authored-by: Emil Ernerfeldt <[email protected]>
  • Loading branch information
CodedNil and emilk authored Feb 5, 2024
1 parent a41a04d commit a5973e5
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 3 deletions.
7 changes: 7 additions & 0 deletions crates/egui-wgpu/src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -923,12 +923,19 @@ fn create_sampler(
epaint::textures::TextureFilter::Nearest => wgpu::FilterMode::Nearest,
epaint::textures::TextureFilter::Linear => wgpu::FilterMode::Linear,
};
let address_mode = match options.wrap_mode {
epaint::textures::TextureWrapMode::ClampToEdge => wgpu::AddressMode::ClampToEdge,
epaint::textures::TextureWrapMode::Repeat => wgpu::AddressMode::Repeat,
epaint::textures::TextureWrapMode::MirroredRepeat => wgpu::AddressMode::MirrorRepeat,
};
device.create_sampler(&wgpu::SamplerDescriptor {
label: Some(&format!(
"egui sampler (mag: {mag_filter:?}, min {min_filter:?})"
)),
mag_filter,
min_filter,
address_mode_u: address_mode,
address_mode_v: address_mode,
..Default::default()
})
}
Expand Down
2 changes: 1 addition & 1 deletion crates/egui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ pub use emath::{
pub use epaint::{
mutex,
text::{FontData, FontDefinitions, FontFamily, FontId, FontTweak},
textures::{TextureFilter, TextureOptions, TexturesDelta},
textures::{TextureFilter, TextureOptions, TextureWrapMode, TexturesDelta},
ClippedPrimitive, ColorImage, FontImage, ImageData, Mesh, PaintCallback, PaintCallbackInfo,
Rounding, Shape, Stroke, TextureHandle, TextureId,
};
Expand Down
18 changes: 16 additions & 2 deletions crates/egui_glow/src/painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,20 @@ impl TextureFilterExt for egui::TextureFilter {
}
}

trait TextureWrapModeExt {
fn glow_code(&self) -> u32;
}

impl TextureWrapModeExt for egui::TextureWrapMode {
fn glow_code(&self) -> u32 {
match self {
Self::ClampToEdge => glow::CLAMP_TO_EDGE,
Self::Repeat => glow::REPEAT,
Self::MirroredRepeat => glow::MIRRORED_REPEAT,
}
}
}

#[derive(Debug)]
pub struct PainterError(String);

Expand Down Expand Up @@ -555,12 +569,12 @@ impl Painter {
self.gl.tex_parameter_i32(
glow::TEXTURE_2D,
glow::TEXTURE_WRAP_S,
glow::CLAMP_TO_EDGE as i32,
options.wrap_mode.glow_code() as i32,
);
self.gl.tex_parameter_i32(
glow::TEXTURE_2D,
glow::TEXTURE_WRAP_T,
glow::CLAMP_TO_EDGE as i32,
options.wrap_mode.glow_code() as i32,
);
check_for_gl_error!(&self.gl, "tex_parameter");

Expand Down
50 changes: 50 additions & 0 deletions crates/epaint/src/textures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,19 +156,52 @@ pub struct TextureOptions {

/// How to filter when minifying (when texels are smaller than pixels).
pub minification: TextureFilter,

/// How to wrap the texture when the texture coordinates are outside the [0, 1] range.
pub wrap_mode: TextureWrapMode,
}

impl TextureOptions {
/// Linear magnification and minification.
pub const LINEAR: Self = Self {
magnification: TextureFilter::Linear,
minification: TextureFilter::Linear,
wrap_mode: TextureWrapMode::ClampToEdge,
};

/// Nearest magnification and minification.
pub const NEAREST: Self = Self {
magnification: TextureFilter::Nearest,
minification: TextureFilter::Nearest,
wrap_mode: TextureWrapMode::ClampToEdge,
};

/// Linear magnification and minification, but with the texture repeated.
pub const LINEAR_REPEAT: Self = Self {
magnification: TextureFilter::Linear,
minification: TextureFilter::Linear,
wrap_mode: TextureWrapMode::Repeat,
};

/// Linear magnification and minification, but with the texture mirrored and repeated.
pub const LINEAR_MIRRORED_REPEAT: Self = Self {
magnification: TextureFilter::Linear,
minification: TextureFilter::Linear,
wrap_mode: TextureWrapMode::MirroredRepeat,
};

/// Nearest magnification and minification, but with the texture repeated.
pub const NEAREST_REPEAT: Self = Self {
magnification: TextureFilter::Nearest,
minification: TextureFilter::Nearest,
wrap_mode: TextureWrapMode::Repeat,
};

/// Nearest magnification and minification, but with the texture mirrored and repeated.
pub const NEAREST_MIRRORED_REPEAT: Self = Self {
magnification: TextureFilter::Nearest,
minification: TextureFilter::Nearest,
wrap_mode: TextureWrapMode::MirroredRepeat,
};
}

Expand All @@ -193,6 +226,23 @@ pub enum TextureFilter {
Linear,
}

/// Defines how textures are wrapped around objects when texture coordinates fall outside the [0, 1] range.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum TextureWrapMode {
/// Stretches the edge pixels to fill beyond the texture's bounds.
///
/// This is what you want to use for a normal image in a GUI.
#[default]
ClampToEdge,

/// Tiles the texture across the surface, repeating it horizontally and vertically.
Repeat,

/// Mirrors the texture with each repetition, creating symmetrical tiling.
MirroredRepeat,
}

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

/// What has been allocated and freed during the last period.
Expand Down

0 comments on commit a5973e5

Please sign in to comment.