imgui-rs/imgui-examples/examples/custom_textures.rs
2024-05-24 15:27:30 -04:00

234 lines
7.8 KiB
Rust

use std::borrow::Cow;
use std::error::Error;
use std::io::Cursor;
use std::rc::Rc;
use glium::{
backend::Facade,
texture::{ClientFormat, RawImage2d},
uniforms::{MagnifySamplerFilter, MinifySamplerFilter, SamplerBehavior},
Texture2d,
};
use image::{jpeg::JpegDecoder, ImageDecoder};
use imgui::*;
use imgui_glium_renderer::Texture;
mod support;
#[derive(Default)]
struct CustomTexturesApp {
my_texture_id: Option<TextureId>,
lenna: Option<Lenna>,
}
struct Lenna {
texture_id: TextureId,
size: [f32; 2],
}
impl CustomTexturesApp {
fn register_textures<F>(
&mut self,
gl_ctx: &F,
textures: &mut Textures<Texture>,
) -> Result<(), Box<dyn Error>>
where
F: Facade,
{
const WIDTH: usize = 100;
const HEIGHT: usize = 100;
if self.my_texture_id.is_none() {
// Generate dummy texture
let mut data = Vec::with_capacity(WIDTH * HEIGHT);
for i in 0..WIDTH {
for j in 0..HEIGHT {
// Insert RGB values
data.push(i as u8);
data.push(j as u8);
data.push((i + j) as u8);
}
}
let raw = RawImage2d {
data: Cow::Owned(data),
width: WIDTH as u32,
height: HEIGHT as u32,
format: ClientFormat::U8U8U8,
};
let gl_texture = Texture2d::new(gl_ctx, raw)?;
let texture = Texture {
texture: Rc::new(gl_texture),
sampler: SamplerBehavior {
magnify_filter: MagnifySamplerFilter::Linear,
minify_filter: MinifySamplerFilter::Linear,
..Default::default()
},
};
let texture_id = textures.insert(texture);
self.my_texture_id = Some(texture_id);
}
if self.lenna.is_none() {
self.lenna = Some(Lenna::new(gl_ctx, textures)?);
}
Ok(())
}
fn show_textures(&self, ui: &Ui) {
ui.window("Hello textures")
.size([400.0, 400.0], Condition::FirstUseEver)
.build(|| {
ui.text("Hello textures!");
if let Some(my_texture_id) = self.my_texture_id {
ui.text("Some generated texture");
Image::new(my_texture_id, [100.0, 100.0]).build(ui);
}
if let Some(lenna) = &self.lenna {
ui.text("Say hello to Lenna.jpg");
lenna.show(ui);
}
// Example of using custom textures on a button
if let Some(lenna) = &self.lenna {
ui.text("The Lenna buttons");
{
ui.invisible_button("Boring Button", [100.0, 100.0]);
// See also `imgui::Ui::style_color`
let tint_none = [1.0, 1.0, 1.0, 1.0];
let tint_green = [0.5, 1.0, 0.5, 1.0];
let tint_red = [1.0, 0.5, 0.5, 1.0];
let tint = match (
ui.is_item_hovered(),
ui.is_mouse_down(imgui::MouseButton::Left),
) {
(false, false) => tint_none,
(false, true) => tint_none,
(true, false) => tint_green,
(true, true) => tint_red,
};
let draw_list = ui.get_window_draw_list();
draw_list
.add_image(lenna.texture_id, ui.item_rect_min(), ui.item_rect_max())
.col(tint)
.build();
}
{
ui.same_line();
// Button using quad positioned image
ui.invisible_button("Exciting Button", [100.0, 100.0]);
// Button bounds
let min = ui.item_rect_min();
let max = ui.item_rect_max();
// get corner coordinates
let tl = [
min[0],
min[1] + (ui.frame_count() as f32 / 10.0).cos() * 10.0,
];
let tr = [
max[0],
min[1] + (ui.frame_count() as f32 / 10.0).sin() * 10.0,
];
let bl = [min[0], max[1]];
let br = max;
let draw_list = ui.get_window_draw_list();
draw_list
.add_image_quad(lenna.texture_id, tl, tr, br, bl)
.build();
}
// Rounded image
{
ui.same_line();
ui.invisible_button("Smooth Button", [100.0, 100.0]);
let draw_list = ui.get_window_draw_list();
draw_list
.add_image_rounded(
lenna.texture_id,
ui.item_rect_min(),
ui.item_rect_max(),
16.0,
)
// Tint brighter for visiblity of corners
.col([2.0, 0.5, 0.5, 1.0])
// Rounding on each corner can be changed separately
.round_top_left(ui.frame_count() / 60 % 4 == 0)
.round_top_right((ui.frame_count() + 1) / 60 % 4 == 1)
.round_bot_right((ui.frame_count() + 3) / 60 % 4 == 2)
.round_bot_left((ui.frame_count() + 2) / 60 % 4 == 3)
.build();
}
}
});
}
}
impl Lenna {
fn new<F>(gl_ctx: &F, textures: &mut Textures<Texture>) -> Result<Self, Box<dyn Error>>
where
F: Facade,
{
let lenna_bytes = include_bytes!("../../resources/Lenna.jpg");
let byte_stream = Cursor::new(lenna_bytes.as_ref());
let decoder = JpegDecoder::new(byte_stream)?;
let (width, height) = decoder.dimensions();
let mut image = vec![0; decoder.total_bytes() as usize];
decoder.read_image(&mut image)?;
let raw = RawImage2d {
data: Cow::Owned(image),
width,
height,
format: ClientFormat::U8U8U8,
};
let gl_texture = Texture2d::new(gl_ctx, raw)?;
let texture = Texture {
texture: Rc::new(gl_texture),
sampler: SamplerBehavior {
magnify_filter: MagnifySamplerFilter::Linear,
minify_filter: MinifySamplerFilter::Linear,
..Default::default()
},
};
let texture_id = textures.insert(texture);
Ok(Lenna {
texture_id,
size: [width as f32, height as f32],
})
}
fn show(&self, ui: &Ui) {
Image::new(self.texture_id, self.size).build(ui);
}
}
fn main() {
let my_app = std::rc::Rc::new(std::cell::RefCell::new(CustomTexturesApp::default()));
let app_clone = my_app.clone();
support::init_with_startup(
file!(),
move |_ctx, renderer, display| {
app_clone
.borrow_mut()
.register_textures(display.get_context(), renderer.textures())
.expect("Failed to register textures");
},
move |_, ui| {
my_app.borrow_mut().show_textures(ui);
},
);
}