use crate::frame::context::UpdateType;
use crate::render::image::ImageSource;
use crate::response::Response;
use crate::size::rect::Rect;
use crate::size::SizeMode;
use crate::ui::Ui;
use crate::vertex::ImageVertex;
use crate::widgets::{Widget, WidgetChange, WidgetSize};
use crate::Size;
use wgpu::util::DeviceExt;
pub struct Image {
id: String,
source: ImageSource,
pub(crate) rect: Rect,
size_mode: SizeMode,
vertices: Vec<ImageVertex>,
vertex_buffer: Option<wgpu::Buffer>,
index_buffer: Option<wgpu::Buffer>,
changed: bool,
}
impl Image {
pub fn new(source: impl Into<ImageSource>) -> Self {
Image {
id: crate::gen_unique_id(),
source: source.into(),
rect: Rect::new(),
size_mode: SizeMode::Auto,
vertices: vec![],
vertex_buffer: None,
index_buffer: None,
changed: false,
}
}
fn reset_size(&mut self, size: Size) {
let (w, h) = self.size_mode.size(size.width as f32, size.height as f32);
self.rect.set_size(w, h);
}
pub fn set_rect(&mut self, rect: Rect) {
self.rect = rect;
}
pub fn with_size(mut self, width: f32, height: f32) -> Self {
self.size_mode = SizeMode::Fix(width, height);
self
}
pub fn set_size(&mut self, width: f32, height: f32) {
self.size_mode = SizeMode::Fix(width, height);
}
pub fn with_id(mut self, id: impl ToString) -> Self {
self.id = id.to_string();
self
}
pub fn set_image(&mut self, source: impl Into<ImageSource>) {
self.source = source.into();
self.changed = true;
}
fn init(&mut self, ui: &mut Ui) {
self.re_init(ui);
}
fn re_init(&mut self, ui: &mut Ui) {
let size = ui.context.render.image.insert_image(&ui.device, &self.source);
self.reset_size(size);
let indices: [u16; 6] = [0, 1, 2, 2, 3, 0];
self.vertices = vec![
ImageVertex::new_coord(self.rect.left_top(), [0.0, 0.0], Size::from(&ui.device.surface_config)),
ImageVertex::new_coord(self.rect.left_bottom(), [0.0, 1.0], Size::from(&ui.device.surface_config)),
ImageVertex::new_coord(self.rect.right_bottom(), [1.0, 1.0], Size::from(&ui.device.surface_config)),
ImageVertex::new_coord(self.rect.right_top(), [1.0, 0.0], Size::from(&ui.device.surface_config))
];
let vertex_buffer = ui.device.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"),
contents: bytemuck::cast_slice(self.vertices.as_slice()),
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
});
self.vertex_buffer = Some(vertex_buffer);
let index_buffer = ui.device.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Index Buffer"),
contents: bytemuck::cast_slice(&indices),
usage: wgpu::BufferUsages::INDEX,
});
self.index_buffer = Some(index_buffer);
}
fn update_buffer(&mut self, ui: &mut Ui) {
if self.changed { ui.widget_changed |= WidgetChange::Value; }
self.changed = false;
if !ui.widget_changed.unchanged() {
self.rect.offset_to_rect(&ui.draw_rect);
for (index, v) in self.vertices.iter_mut().enumerate() {
match index {
0 => v.position = self.rect.left_top(),
1 => v.position = self.rect.left_bottom(),
2 => v.position = self.rect.right_bottom(),
3 => v.position = self.rect.right_top(),
_ => {}
}
v.screen_size = [ui.device.surface_config.width as f32, ui.device.surface_config.height as f32];
}
ui.device.queue.write_buffer(
self.vertex_buffer.as_ref().unwrap(), 0,
bytemuck::cast_slice(self.vertices.as_slice()));
ui.context.render.image.insert_image(&ui.device, &self.source);
}
}
pub(crate) fn redraw(&mut self, ui: &mut Ui) {
self.update_buffer(ui);
let pass = ui.pass.as_mut().unwrap();
ui.context.render.image.render(
&self.source.uri(),
self.vertex_buffer.as_ref().unwrap(),
self.index_buffer.as_ref().unwrap(),
pass,
);
}
}
impl Widget for Image {
fn update(&mut self, ui: &mut Ui) -> Response<'_> {
match ui.update_type {
UpdateType::Draw => self.redraw(ui),
UpdateType::Init => self.init(ui),
UpdateType::ReInit => self.re_init(ui),
_ => {}
}
Response::new(&self.id, WidgetSize::same(self.rect.width(), self.rect.height()))
}
}