[user textures] Add custom texture/image support
* Each Traingles mesh comes with a TextureId * ui.image(...) to show an image/texture * Up to backend what to do with user textures
This commit is contained in:
parent
5ba420988f
commit
02ef0cd9d5
10 changed files with 201 additions and 72 deletions
5
TODO.md
5
TODO.md
|
@ -53,9 +53,8 @@ TODO-list for the Egui project. If you looking for something to do, look here.
|
||||||
* [ ] Positioning preference: `window.preference(Top, Right)`
|
* [ ] Positioning preference: `window.preference(Top, Right)`
|
||||||
* [ ] Keeping right/bottom on expand. Maybe cover jitteryness with quick animation?
|
* [ ] Keeping right/bottom on expand. Maybe cover jitteryness with quick animation?
|
||||||
* [ ] Make auto-positioning of windows respect permanent side-bars.
|
* [ ] Make auto-positioning of windows respect permanent side-bars.
|
||||||
* [ ] Image support
|
* [/] Image support
|
||||||
* [ ] user-chosen texture ids (so people can show thing with mipmaps and whatnot)
|
* [x] Show user textures
|
||||||
* [ ] `enum TextureId { Egui, User(u64) }` added to `Triangles`
|
|
||||||
* [ ] API for creating a texture managed by Egui
|
* [ ] API for creating a texture managed by Egui
|
||||||
* Backend-agnostic. Good for people doing Egui-apps (games etc).
|
* Backend-agnostic. Good for people doing Egui-apps (games etc).
|
||||||
* [ ] Convert font texture to RGBA, or communicate format in initialization?
|
* [ ] Convert font texture to RGBA, or communicate format in initialization?
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
containers::show_tooltip,
|
containers::show_tooltip,
|
||||||
math::*,
|
math::*,
|
||||||
paint::{self, color::WHITE, PaintCmd, Texture, Triangles, Vertex},
|
paint::{self, color::WHITE, PaintCmd, Texture, Triangles},
|
||||||
*,
|
*,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,18 +21,8 @@ impl Texture {
|
||||||
size *= ui.available().width() / size.x;
|
size *= ui.available().width() / size.x;
|
||||||
}
|
}
|
||||||
let rect = ui.allocate_space(size);
|
let rect = ui.allocate_space(size);
|
||||||
let top_left = Vertex {
|
|
||||||
pos: rect.min,
|
|
||||||
uv: pos2(0.0, 0.0),
|
|
||||||
color: WHITE,
|
|
||||||
};
|
|
||||||
let bottom_right = Vertex {
|
|
||||||
pos: rect.max,
|
|
||||||
uv: pos2(1.0, 1.0),
|
|
||||||
color: WHITE,
|
|
||||||
};
|
|
||||||
let mut triangles = Triangles::default();
|
let mut triangles = Triangles::default();
|
||||||
triangles.add_rect(top_left, bottom_right);
|
triangles.add_rect_with_uv(rect, [pos2(0.0, 0.0), pos2(1.0, 1.0)].into(), WHITE);
|
||||||
ui.painter().add(PaintCmd::Triangles(triangles));
|
ui.painter().add(PaintCmd::Triangles(triangles));
|
||||||
|
|
||||||
let tex_w = self.width as f32;
|
let tex_w = self.width as f32;
|
||||||
|
@ -49,18 +39,12 @@ impl Texture {
|
||||||
let u = u.max(texel_radius).min(tex_w - texel_radius);
|
let u = u.max(texel_radius).min(tex_w - texel_radius);
|
||||||
let v = v.max(texel_radius).min(tex_h - texel_radius);
|
let v = v.max(texel_radius).min(tex_h - texel_radius);
|
||||||
|
|
||||||
let top_left = Vertex {
|
let uv_rect = Rect::from_min_max(
|
||||||
pos: zoom_rect.min,
|
pos2((u - texel_radius) / tex_w, (v - texel_radius) / tex_h),
|
||||||
uv: pos2((u - texel_radius) / tex_w, (v - texel_radius) / tex_h),
|
pos2((u + texel_radius) / tex_w, (v + texel_radius) / tex_h),
|
||||||
color: WHITE,
|
);
|
||||||
};
|
|
||||||
let bottom_right = Vertex {
|
|
||||||
pos: zoom_rect.max,
|
|
||||||
uv: pos2((u + texel_radius) / tex_w, (v + texel_radius) / tex_h),
|
|
||||||
color: WHITE,
|
|
||||||
};
|
|
||||||
let mut triangles = Triangles::default();
|
let mut triangles = Triangles::default();
|
||||||
triangles.add_rect(top_left, bottom_right);
|
triangles.add_rect_with_uv(zoom_rect, uv_rect, WHITE);
|
||||||
ui.painter().add(PaintCmd::Triangles(triangles));
|
ui.painter().add(PaintCmd::Triangles(triangles));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ pub use {
|
||||||
layout::*,
|
layout::*,
|
||||||
math::*,
|
math::*,
|
||||||
memory::Memory,
|
memory::Memory,
|
||||||
paint::{color, PaintJobs, Rgba, Srgba, Stroke, TextStyle, Texture},
|
paint::{color, PaintJobs, Rgba, Srgba, Stroke, TextStyle, Texture, TextureId},
|
||||||
painter::Painter,
|
painter::Painter,
|
||||||
style::Style,
|
style::Style,
|
||||||
types::*,
|
types::*,
|
||||||
|
|
|
@ -199,3 +199,10 @@ impl std::fmt::Debug for Rect {
|
||||||
write!(f, "[{:?} - {:?}]", self.min, self.max)
|
write!(f, "[{:?} - {:?}]", self.min, self.max)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// from (min, max) or (left top, right bottom)
|
||||||
|
impl From<[Pos2; 2]> for Rect {
|
||||||
|
fn from([min, max]: [Pos2; 2]) -> Self {
|
||||||
|
Self { min, max }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,6 @@ pub use {
|
||||||
color::{Rgba, Srgba},
|
color::{Rgba, Srgba},
|
||||||
command::{PaintCmd, Stroke},
|
command::{PaintCmd, Stroke},
|
||||||
fonts::{FontDefinitions, Fonts, TextStyle},
|
fonts::{FontDefinitions, Fonts, TextStyle},
|
||||||
tessellator::{PaintJobs, PaintOptions, Triangles, Vertex, WHITE_UV},
|
tessellator::{PaintJobs, PaintOptions, TextureId, Triangles, Vertex, WHITE_UV},
|
||||||
texture_atlas::Texture,
|
texture_atlas::Texture,
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,6 +41,10 @@ impl Srgba {
|
||||||
Self([0, 0, 0, a])
|
Self([0, 0, 0, a])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn white_alpha(a: u8) -> Self {
|
||||||
|
Rgba::white_alpha(linear_from_alpha_byte(a)).into()
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn additive_luminance(l: u8) -> Self {
|
pub const fn additive_luminance(l: u8) -> Self {
|
||||||
Self([l, l, l, 0])
|
Self([l, l, l, 0])
|
||||||
}
|
}
|
||||||
|
@ -49,6 +53,27 @@ impl Srgba {
|
||||||
pub fn to_opaque(self) -> Self {
|
pub fn to_opaque(self) -> Self {
|
||||||
Rgba::from(self).to_opaque().into()
|
Rgba::from(self).to_opaque().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn r(&self) -> u8 {
|
||||||
|
self.0[0]
|
||||||
|
}
|
||||||
|
pub fn g(&self) -> u8 {
|
||||||
|
self.0[1]
|
||||||
|
}
|
||||||
|
pub fn b(&self) -> u8 {
|
||||||
|
self.0[2]
|
||||||
|
}
|
||||||
|
pub fn a(&self) -> u8 {
|
||||||
|
self.0[3]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_array(&self) -> [u8; 4] {
|
||||||
|
[self.r(), self.g(), self.b(), self.a()]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_tuple(&self) -> (u8, u8, u8, u8) {
|
||||||
|
(self.r(), self.g(), self.b(), self.a())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
|
@ -14,6 +14,24 @@ use {
|
||||||
crate::math::*,
|
crate::math::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// What texture to use in a `Triangles` mesh.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum TextureId {
|
||||||
|
/// The Egui font texture.
|
||||||
|
/// If you don't want to use a texture, pick this and the `WHITE_UV` for uv-coord.
|
||||||
|
Egui,
|
||||||
|
|
||||||
|
/// Your own texture, defined in any which way you want.
|
||||||
|
/// Egui won't care. The backend renderer will presumably use this to look up what texture to use.
|
||||||
|
User(u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TextureId {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Egui
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The UV coordinate of a white region of the texture mesh.
|
/// The UV coordinate of a white region of the texture mesh.
|
||||||
/// The default Egui texture has the top-left corner pixel fully white.
|
/// The default Egui texture has the top-left corner pixel fully white.
|
||||||
/// You need need use a clamping texture sampler for this to work
|
/// You need need use a clamping texture sampler for this to work
|
||||||
|
@ -44,8 +62,12 @@ pub struct Vertex {
|
||||||
pub struct Triangles {
|
pub struct Triangles {
|
||||||
/// Draw as triangles (i.e. the length is always multiple of three).
|
/// Draw as triangles (i.e. the length is always multiple of three).
|
||||||
pub indices: Vec<u32>,
|
pub indices: Vec<u32>,
|
||||||
|
|
||||||
/// The vertex data indexed by `indices`.
|
/// The vertex data indexed by `indices`.
|
||||||
pub vertices: Vec<Vertex>,
|
pub vertices: Vec<Vertex>,
|
||||||
|
|
||||||
|
/// The texture to use when drawing these triangles
|
||||||
|
pub texture_id: TextureId,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A clip triangle and some textured triangles.
|
/// A clip triangle and some textured triangles.
|
||||||
|
@ -58,14 +80,34 @@ pub type PaintJobs = Vec<PaintJob>;
|
||||||
|
|
||||||
/// ## Helpers for adding
|
/// ## Helpers for adding
|
||||||
impl Triangles {
|
impl Triangles {
|
||||||
|
pub fn with_texture(texture_id: TextureId) -> Self {
|
||||||
|
Self {
|
||||||
|
texture_id,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Are all indices within the bounds of the contained vertices?
|
/// Are all indices within the bounds of the contained vertices?
|
||||||
pub fn is_valid(&self) -> bool {
|
pub fn is_valid(&self) -> bool {
|
||||||
let n = self.vertices.len() as u32;
|
let n = self.vertices.len() as u32;
|
||||||
self.indices.iter().all(|&i| i < n)
|
self.indices.iter().all(|&i| i < n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.indices.is_empty() && self.vertices.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
/// Append all the indices and vertices of `other` to `self`.
|
/// Append all the indices and vertices of `other` to `self`.
|
||||||
pub fn append(&mut self, other: &Triangles) {
|
pub fn append(&mut self, other: &Triangles) {
|
||||||
|
if self.is_empty() {
|
||||||
|
self.texture_id = other.texture_id;
|
||||||
|
} else {
|
||||||
|
assert_eq!(
|
||||||
|
self.texture_id, other.texture_id,
|
||||||
|
"Can't merge Triangles using different textures"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let index_offset = self.vertices.len() as u32;
|
let index_offset = self.vertices.len() as u32;
|
||||||
for index in &other.indices {
|
for index in &other.indices {
|
||||||
self.indices.push(index_offset + index);
|
self.indices.push(index_offset + index);
|
||||||
|
@ -74,6 +116,7 @@ impl Triangles {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn colored_vertex(&mut self, pos: Pos2, color: Srgba) {
|
pub fn colored_vertex(&mut self, pos: Pos2, color: Srgba) {
|
||||||
|
debug_assert!(self.texture_id == TextureId::Egui);
|
||||||
self.vertices.push(Vertex {
|
self.vertices.push(Vertex {
|
||||||
pos,
|
pos,
|
||||||
uv: WHITE_UV,
|
uv: WHITE_UV,
|
||||||
|
@ -100,44 +143,42 @@ impl Triangles {
|
||||||
self.vertices.reserve(additional);
|
self.vertices.reserve(additional);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uniformly colored rectangle.
|
/// Rectangle with a texture and color.
|
||||||
pub fn add_rect(&mut self, top_left: Vertex, bottom_right: Vertex) {
|
pub fn add_rect_with_uv(&mut self, pos: Rect, uv: Rect, color: Srgba) {
|
||||||
debug_assert_eq!(top_left.color, bottom_right.color);
|
|
||||||
|
|
||||||
let idx = self.vertices.len() as u32;
|
let idx = self.vertices.len() as u32;
|
||||||
self.add_triangle(idx + 0, idx + 1, idx + 2);
|
self.add_triangle(idx + 0, idx + 1, idx + 2);
|
||||||
self.add_triangle(idx + 2, idx + 1, idx + 3);
|
self.add_triangle(idx + 2, idx + 1, idx + 3);
|
||||||
|
|
||||||
let top_right = Vertex {
|
let right_top = Vertex {
|
||||||
pos: pos2(bottom_right.pos.x, top_left.pos.y),
|
pos: pos.right_top(),
|
||||||
uv: pos2(bottom_right.uv.x, top_left.uv.y),
|
uv: uv.right_top(),
|
||||||
color: top_left.color,
|
color,
|
||||||
};
|
};
|
||||||
let botom_left = Vertex {
|
let left_top = Vertex {
|
||||||
pos: pos2(top_left.pos.x, bottom_right.pos.y),
|
pos: pos.left_top(),
|
||||||
uv: pos2(top_left.uv.x, bottom_right.uv.y),
|
uv: uv.left_top(),
|
||||||
color: top_left.color,
|
color,
|
||||||
};
|
};
|
||||||
self.vertices.push(top_left);
|
let left_bottom = Vertex {
|
||||||
self.vertices.push(top_right);
|
pos: pos.left_bottom(),
|
||||||
self.vertices.push(botom_left);
|
uv: uv.left_bottom(),
|
||||||
self.vertices.push(bottom_right);
|
color,
|
||||||
|
};
|
||||||
|
let right_bottom = Vertex {
|
||||||
|
pos: pos.right_bottom(),
|
||||||
|
uv: uv.right_bottom(),
|
||||||
|
color,
|
||||||
|
};
|
||||||
|
self.vertices.push(left_top);
|
||||||
|
self.vertices.push(right_top);
|
||||||
|
self.vertices.push(left_bottom);
|
||||||
|
self.vertices.push(right_bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uniformly colored rectangle.
|
/// Uniformly colored rectangle.
|
||||||
pub fn add_colored_rect(&mut self, rect: Rect, color: Srgba) {
|
pub fn add_colored_rect(&mut self, rect: Rect, color: Srgba) {
|
||||||
self.add_rect(
|
debug_assert!(self.texture_id == TextureId::Egui);
|
||||||
Vertex {
|
self.add_rect_with_uv(rect, [WHITE_UV, WHITE_UV].into(), color)
|
||||||
pos: rect.min,
|
|
||||||
uv: WHITE_UV,
|
|
||||||
color,
|
|
||||||
},
|
|
||||||
Vertex {
|
|
||||||
pos: rect.max,
|
|
||||||
uv: WHITE_UV,
|
|
||||||
color,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is for platforms that only support 16-bit index buffers.
|
/// This is for platforms that only support 16-bit index buffers.
|
||||||
|
@ -189,6 +230,7 @@ impl Triangles {
|
||||||
.map(|vi| vi - min_vindex)
|
.map(|vi| vi - min_vindex)
|
||||||
.collect(),
|
.collect(),
|
||||||
vertices: self.vertices[(min_vindex as usize)..=(max_vindex as usize)].to_vec(),
|
vertices: self.vertices[(min_vindex as usize)..=(max_vindex as usize)].to_vec(),
|
||||||
|
texture_id: self.texture_id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
output
|
output
|
||||||
|
@ -703,19 +745,17 @@ fn tessellate_paint_command(
|
||||||
for x_offset in line.x_offsets.iter().take(line.x_offsets.len() - 1) {
|
for x_offset in line.x_offsets.iter().take(line.x_offsets.len() - 1) {
|
||||||
let c = chars.next().unwrap();
|
let c = chars.next().unwrap();
|
||||||
if let Some(glyph) = font.uv_rect(c) {
|
if let Some(glyph) = font.uv_rect(c) {
|
||||||
let mut top_left = Vertex {
|
let mut left_top =
|
||||||
pos: pos + glyph.offset + vec2(*x_offset, line.y_min) + text_offset,
|
pos + glyph.offset + vec2(*x_offset, line.y_min) + text_offset;
|
||||||
uv: pos2(glyph.min.0 as f32 / tex_w, glyph.min.1 as f32 / tex_h),
|
left_top.x = font.round_to_pixel(left_top.x); // Pixel-perfection.
|
||||||
color,
|
left_top.y = font.round_to_pixel(left_top.y); // Pixel-perfection.
|
||||||
};
|
|
||||||
top_left.pos.x = font.round_to_pixel(top_left.pos.x); // Pixel-perfection.
|
let pos = Rect::from_min_max(left_top, left_top + glyph.size);
|
||||||
top_left.pos.y = font.round_to_pixel(top_left.pos.y); // Pixel-perfection.
|
let uv = Rect::from_min_max(
|
||||||
let bottom_right = Vertex {
|
pos2(glyph.min.0 as f32 / tex_w, glyph.min.1 as f32 / tex_h),
|
||||||
pos: top_left.pos + glyph.size,
|
pos2(glyph.max.0 as f32 / tex_w, glyph.max.1 as f32 / tex_h),
|
||||||
uv: pos2(glyph.max.0 as f32 / tex_w, glyph.max.1 as f32 / tex_h),
|
);
|
||||||
color,
|
out.add_rect_with_uv(pos, uv, color);
|
||||||
};
|
|
||||||
out.add_rect(top_left, bottom_right);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -747,7 +787,16 @@ pub fn tessellate_paint_commands(
|
||||||
for (clip_rect, cmd) in commands {
|
for (clip_rect, cmd) in commands {
|
||||||
// TODO: cull(clip_rect, cmd)
|
// TODO: cull(clip_rect, cmd)
|
||||||
|
|
||||||
if jobs.is_empty() || jobs.last().unwrap().0 != clip_rect {
|
if let PaintCmd::Triangles(triangles) = cmd {
|
||||||
|
// Assume non-Egui texture, which means own paint job:
|
||||||
|
jobs.push((clip_rect, triangles));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if jobs.is_empty()
|
||||||
|
|| jobs.last().unwrap().0 != clip_rect
|
||||||
|
|| jobs.last().unwrap().1.texture_id != TextureId::Egui
|
||||||
|
{
|
||||||
jobs.push((clip_rect, Triangles::default()));
|
jobs.push((clip_rect, Triangles::default()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -489,6 +489,11 @@ impl Ui {
|
||||||
let rect = self.allocate_space(desired_size);
|
let rect = self.allocate_space(desired_size);
|
||||||
self.painter_at(rect)
|
self.painter_at(rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Show an image here with the given size
|
||||||
|
pub fn image(&mut self, texture_id: TextureId, desired_size: Vec2) -> Response {
|
||||||
|
self.add(Image::new(texture_id, desired_size))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Colors
|
/// # Colors
|
||||||
|
|
|
@ -9,10 +9,11 @@
|
||||||
use crate::{layout::Direction, *};
|
use crate::{layout::Direction, *};
|
||||||
|
|
||||||
pub mod color_picker;
|
pub mod color_picker;
|
||||||
|
mod image;
|
||||||
mod slider;
|
mod slider;
|
||||||
pub(crate) mod text_edit;
|
pub(crate) mod text_edit;
|
||||||
|
|
||||||
pub use {slider::*, text_edit::*};
|
pub use {image::Image, slider::*, text_edit::*};
|
||||||
|
|
||||||
use paint::*;
|
use paint::*;
|
||||||
|
|
||||||
|
|
59
egui/src/widgets/image.rs
Normal file
59
egui/src/widgets/image.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
pub struct Image {
|
||||||
|
texture_id: TextureId,
|
||||||
|
desired_size: Vec2,
|
||||||
|
bg_fill: Srgba,
|
||||||
|
tint: Srgba,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Image {
|
||||||
|
pub fn new(texture_id: TextureId, desired_size: Vec2) -> Self {
|
||||||
|
Self {
|
||||||
|
texture_id,
|
||||||
|
desired_size,
|
||||||
|
tint: color::WHITE,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A solid color to put behind the image. Useful for transparent images.
|
||||||
|
pub fn bg_fill(mut self, bg_fill: Srgba) -> Self {
|
||||||
|
self.bg_fill = bg_fill;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Multiply image color with this. Default is WHITE (no tint).
|
||||||
|
pub fn tint(mut self, tint: Srgba) -> Self {
|
||||||
|
self.tint = tint;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for Image {
|
||||||
|
fn ui(self, ui: &mut Ui) -> Response {
|
||||||
|
use paint::*;
|
||||||
|
let Self {
|
||||||
|
texture_id,
|
||||||
|
desired_size,
|
||||||
|
bg_fill,
|
||||||
|
tint,
|
||||||
|
} = self;
|
||||||
|
let rect = ui.allocate_space(desired_size);
|
||||||
|
if bg_fill != Default::default() {
|
||||||
|
let mut triangles = Triangles::default();
|
||||||
|
triangles.add_colored_rect(rect, bg_fill);
|
||||||
|
ui.painter().add(PaintCmd::Triangles(triangles));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// TODO: builder pattern for Triangles
|
||||||
|
let uv = [pos2(0.0, 0.0), pos2(1.0, 1.0)];
|
||||||
|
let mut triangles = Triangles::with_texture(texture_id);
|
||||||
|
triangles.add_rect_with_uv(rect, uv.into(), tint);
|
||||||
|
ui.painter().add(PaintCmd::Triangles(triangles));
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.interact_hover(rect)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue