Working HEIF, working aspect ratio, resize
This commit is contained in:
parent
ed66f17139
commit
b2dc693d0e
48
Cargo.lock
generated
48
Cargo.lock
generated
@ -1553,6 +1553,17 @@ dependencies = [
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumn"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.3"
|
||||
@ -1788,6 +1799,12 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "four-cc"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "795cbfc56d419a7ce47ccbb7504dd9a5b7c484c083c356e797de08bd988d9629"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.31"
|
||||
@ -2666,6 +2683,7 @@ dependencies = [
|
||||
"iced",
|
||||
"image 0.25.6",
|
||||
"itertools 0.12.1",
|
||||
"libheif-rs",
|
||||
"memmap2",
|
||||
"minifb",
|
||||
"pollster",
|
||||
@ -3019,6 +3037,30 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libheif-rs"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4a26370abb4723a3ce73083e479b98017604206cadb0e35da5eac4813600d85"
|
||||
dependencies = [
|
||||
"enumn",
|
||||
"four-cc",
|
||||
"libc",
|
||||
"libheif-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libheif-sys"
|
||||
version = "3.1.0+1.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e663db80d4272b60c066c5a9d17370ffa0433a31d424152f95f1e1effb9b3860"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.4"
|
||||
@ -5363,6 +5405,12 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
version = "0.1.1"
|
||||
|
@ -31,6 +31,7 @@ wgpu = "24.0.3"
|
||||
# winit = "0.30.9"
|
||||
zune-image = {version = "0.4.15", features = ["all"]}
|
||||
bytemuck = "1.22.0"
|
||||
libheif-rs = "1.1.0"
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
debug = false
|
||||
|
84
src/app.rs
84
src/app.rs
@ -1,14 +1,11 @@
|
||||
use crate::egui_tools::EguiRenderer;
|
||||
use eframe::WindowAttributes;
|
||||
use egui::{Event, Key};
|
||||
use egui_wgpu::wgpu::SurfaceError;
|
||||
use egui_wgpu::{ScreenDescriptor, wgpu};
|
||||
use imflow::store::ImageStore;
|
||||
use std::any::Any;
|
||||
use std::path::PathBuf;
|
||||
use std::process::exit;
|
||||
use std::sync::Arc;
|
||||
use std::time;
|
||||
use wgpu::util::DeviceExt;
|
||||
use wgpu::{PipelineCompilationOptions, SurfaceConfiguration};
|
||||
use winit::application::ApplicationHandler;
|
||||
@ -23,20 +20,28 @@ use winit::window::{Window, WindowId};
|
||||
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
struct Transforms {
|
||||
transform: [f32; 16], // 4x4 matrix
|
||||
width: u32,
|
||||
height: u32,
|
||||
_padding1: u32,
|
||||
_padding2: u32,
|
||||
}
|
||||
|
||||
struct TransformData {
|
||||
pub(crate) struct TransformData {
|
||||
pan_x: f32,
|
||||
pan_y: f32,
|
||||
zoom: f32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
fn create_transform_matrix(data: &TransformData) -> [f32; 16] {
|
||||
fn create_transform_matrix(data: &TransformData, scale_x: f32, scale_y: f32) -> [f32; 16] {
|
||||
const ZOOM_MULTIPLIER: f32 = 3.0;
|
||||
let zoom = data.zoom.powf(ZOOM_MULTIPLIER);
|
||||
[
|
||||
zoom, 0.0, 0.0, 0.0, 0.0, zoom, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, data.pan_x, data.pan_y, 0.0,
|
||||
1.0,
|
||||
zoom * scale_x, 0.0, 0.0, 0.0,
|
||||
0.0, zoom * scale_y, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
data.pan_x, data.pan_y, 0.0, 1.0,
|
||||
]
|
||||
}
|
||||
|
||||
@ -62,7 +67,7 @@ fn setup_texture(
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
||||
view_formats: &[],
|
||||
});
|
||||
@ -101,7 +106,7 @@ fn setup_texture(
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 2,
|
||||
visibility: wgpu::ShaderStages::VERTEX,
|
||||
visibility: wgpu::ShaderStages::all(),
|
||||
ty: wgpu::BindingType::Buffer {
|
||||
ty: wgpu::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: false,
|
||||
@ -225,7 +230,7 @@ impl AppState {
|
||||
window: &Window,
|
||||
width: u32,
|
||||
height: u32,
|
||||
path: PathBuf
|
||||
path: PathBuf,
|
||||
) -> Self {
|
||||
let power_pref = wgpu::PowerPreference::default();
|
||||
let adapter = instance
|
||||
@ -279,12 +284,15 @@ impl AppState {
|
||||
let store = ImageStore::new(path);
|
||||
|
||||
let (image_texture, bind_group, render_pipeline, transform_buffer) =
|
||||
setup_texture(&device, surface_config.clone(), 6000, 4000);
|
||||
// setup_texture(&device, surface_config.clone(), 6000, 4000);
|
||||
setup_texture(&device, surface_config.clone(), 8192, 8192);
|
||||
|
||||
let transform_data = TransformData {
|
||||
pan_x: 0.0,
|
||||
pan_y: 0.0,
|
||||
zoom: 1.0,
|
||||
width: 10000,
|
||||
height: 10000,
|
||||
};
|
||||
|
||||
Self {
|
||||
@ -314,7 +322,7 @@ pub struct App {
|
||||
instance: wgpu::Instance,
|
||||
state: Option<AppState>,
|
||||
window: Option<Arc<Window>>,
|
||||
path: PathBuf
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl App {
|
||||
@ -324,7 +332,7 @@ impl App {
|
||||
instance,
|
||||
state: None,
|
||||
window: None,
|
||||
path
|
||||
path,
|
||||
}
|
||||
}
|
||||
|
||||
@ -346,7 +354,7 @@ impl App {
|
||||
&window,
|
||||
initial_width,
|
||||
initial_width,
|
||||
self.path.clone()
|
||||
self.path.clone(),
|
||||
)
|
||||
.await;
|
||||
|
||||
@ -362,6 +370,7 @@ impl App {
|
||||
if width > 0 && height > 0 {
|
||||
self.state.as_mut().unwrap().resize_surface(width, height);
|
||||
}
|
||||
self.pan_zoom(0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
pub fn update_texture(&mut self) {
|
||||
@ -369,7 +378,7 @@ impl App {
|
||||
|
||||
state.store.check_loaded_images();
|
||||
let imbuf = if let Some(full) = state.store.get_current_image() {
|
||||
println!("full");
|
||||
// println!("full");
|
||||
full
|
||||
} else {
|
||||
state.store.get_thumbnail()
|
||||
@ -378,11 +387,15 @@ impl App {
|
||||
let height = imbuf.height as u32;
|
||||
let buffer_u8 = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
imbuf.argb_buffer.as_ptr() as *const u8,
|
||||
imbuf.argb_buffer.len() * 4,
|
||||
imbuf.rgba_buffer.as_ptr() as *const u8,
|
||||
imbuf.rgba_buffer.len() * 4,
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
state.transform_data.width = width;
|
||||
state.transform_data.height = height;
|
||||
|
||||
state.queue.write_texture(
|
||||
wgpu::TexelCopyTextureInfo {
|
||||
texture: &state.image_texture,
|
||||
@ -402,18 +415,38 @@ impl App {
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
);
|
||||
|
||||
self.pan_zoom(0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
pub fn pan_zoom(&mut self, zoom_delta: f32, pan_x: f32, pan_y: f32) {
|
||||
let state = self.state.as_mut().unwrap();
|
||||
|
||||
let image_aspect_ratio = (state.transform_data.width as f32) / (state.transform_data.height as f32);
|
||||
let window_size = self.window.as_ref().unwrap().inner_size();
|
||||
let window_aspect_ratio = window_size.width as f32 / window_size.height as f32;
|
||||
let mut scale_x = 1.0;
|
||||
let mut scale_y = 1.0;
|
||||
if window_aspect_ratio > image_aspect_ratio {
|
||||
scale_x = image_aspect_ratio / window_aspect_ratio;
|
||||
} else {
|
||||
scale_y = window_aspect_ratio / image_aspect_ratio;
|
||||
}
|
||||
|
||||
state.transform_data.zoom = (state.transform_data.zoom + zoom_delta).clamp(1.0, 20.0);
|
||||
state.transform_data.pan_x += pan_x;
|
||||
state.transform_data.pan_y += pan_y;
|
||||
let transform = create_transform_matrix(&state.transform_data);
|
||||
let transform = create_transform_matrix(&state.transform_data, scale_x, scale_y);
|
||||
state.queue.write_buffer(
|
||||
&state.transform_buffer,
|
||||
0,
|
||||
bytemuck::cast_slice(&[Transforms { transform }]),
|
||||
bytemuck::cast_slice(&[Transforms {
|
||||
transform,
|
||||
width: state.transform_data.width,
|
||||
height: state.transform_data.height,
|
||||
_padding1: 0,
|
||||
_padding2: 0,
|
||||
}]),
|
||||
);
|
||||
}
|
||||
|
||||
@ -473,7 +506,7 @@ impl App {
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color {
|
||||
r: 0.0,
|
||||
g: 1.0, // Green
|
||||
g: 0.0, // Green
|
||||
b: 0.0,
|
||||
a: 1.0,
|
||||
}),
|
||||
@ -611,7 +644,7 @@ impl ApplicationHandler for App {
|
||||
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||
let attributes = Window::default_attributes()
|
||||
.with_base_size(LogicalSize::new(2000, 4000))
|
||||
.with_resizable(false);
|
||||
.with_resizable(true);
|
||||
let window = event_loop.create_window(attributes).unwrap();
|
||||
pollster::block_on(self.set_window(window));
|
||||
}
|
||||
@ -630,7 +663,7 @@ impl ApplicationHandler for App {
|
||||
event_loop.exit();
|
||||
}
|
||||
WindowEvent::RedrawRequested => {
|
||||
let start = time::Instant::now();
|
||||
// let start = time::Instant::now();
|
||||
self.handle_redraw();
|
||||
// println!("Updated in: {}ms", start.elapsed().as_millis());
|
||||
// Extract the events by cloning them from the input context
|
||||
@ -677,12 +710,7 @@ impl ApplicationHandler for App {
|
||||
Key::Escape => exit(0),
|
||||
_ => {}
|
||||
}
|
||||
} else if let Event::MouseWheel {
|
||||
unit,
|
||||
delta,
|
||||
modifiers,
|
||||
} = e
|
||||
{
|
||||
} else if let Event::MouseWheel { delta, .. } = e {
|
||||
self.pan_zoom(delta.y * 0.2, 0.0, 0.0);
|
||||
} else if let Event::PointerMoved(pos) = e {
|
||||
if keys_down.contains(&Key::Tab) {
|
||||
|
151
src/image.rs
151
src/image.rs
@ -1,6 +1,7 @@
|
||||
use iced::widget::image::Handle;
|
||||
use image::DynamicImage;
|
||||
use image::imageops::FilterType;
|
||||
use libheif_rs::{HeifContext, LibHeif, RgbChroma};
|
||||
use rexiv2::Metadata;
|
||||
use zune_image::codecs::jpeg::JpegDecoder;
|
||||
use zune_image::codecs::qoi::zune_core::colorspace::ColorSpace;
|
||||
@ -17,7 +18,7 @@ use std::time::Instant;
|
||||
pub struct ImflowImageBuffer {
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub argb_buffer: Vec<u32>,
|
||||
pub rgba_buffer: Vec<u32>,
|
||||
pub rating: i32,
|
||||
}
|
||||
|
||||
@ -25,11 +26,7 @@ pub fn create_iced_handle(width: u32, height: u32, rgba: Vec<u8>) -> Handle {
|
||||
Handle::from_rgba(width, height, rgba)
|
||||
}
|
||||
|
||||
fn get_rating(filename: PathBuf) -> i32 {
|
||||
// if !path_exists(filename.clone()) {
|
||||
// anyhow::bail!("File doesn't exist");
|
||||
// }
|
||||
|
||||
fn get_rating(filename: &PathBuf) -> i32 {
|
||||
// // Use xmp-toolkit for video files
|
||||
// if is_video(&filename) {
|
||||
// return Ok(read_rating_xmp(filename.clone()).unwrap_or(0));
|
||||
@ -46,12 +43,19 @@ fn get_rating(filename: PathBuf) -> i32 {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_image(path: PathBuf) -> ImflowImageBuffer {
|
||||
pub fn load_image(path: &PathBuf) -> ImflowImageBuffer {
|
||||
let total_start = Instant::now();
|
||||
|
||||
if is_heif(path) {
|
||||
let img = load_heif(path, false);
|
||||
let total_time = total_start.elapsed();
|
||||
println!("Total HEIF loading time: {:?}", total_time);
|
||||
return img;
|
||||
}
|
||||
|
||||
let file = read(path.clone()).unwrap();
|
||||
let mut decoder = JpegDecoder::new(&file);
|
||||
let options = DecoderOptions::new_fast().jpeg_set_out_colorspace(ColorSpace::BGRA);
|
||||
let options = DecoderOptions::new_fast().jpeg_set_out_colorspace(ColorSpace::RGBA);
|
||||
decoder.set_options(options);
|
||||
|
||||
decoder.decode_headers().unwrap();
|
||||
@ -80,30 +84,28 @@ pub fn load_image(path: PathBuf) -> ImflowImageBuffer {
|
||||
ImflowImageBuffer {
|
||||
width,
|
||||
height,
|
||||
argb_buffer: buffer_u32,
|
||||
rgba_buffer: buffer_u32,
|
||||
rating,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_to_argb_buffer(img: DynamicImage) -> Vec<u32> {
|
||||
let flat = img.into_rgba8();
|
||||
let buf = flat.as_raw();
|
||||
|
||||
buf.chunks_exact(4)
|
||||
.map(|rgba| {
|
||||
let r = rgba[0] as u32;
|
||||
let g = rgba[1] as u32;
|
||||
let b = rgba[2] as u32;
|
||||
r << 16 | g << 8 | b
|
||||
})
|
||||
.collect()
|
||||
pub fn image_to_rgba_buffer(img: DynamicImage) -> Vec<u32> {
|
||||
let flat = img.to_rgba8();
|
||||
let mut buffer = flat.to_vec();
|
||||
unsafe {
|
||||
Vec::from_raw_parts(
|
||||
buffer.as_mut_ptr() as *mut u32,
|
||||
buffer.len() / 4,
|
||||
buffer.len() / 4,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_available_images(dir: PathBuf) -> Vec<PathBuf> {
|
||||
let mut files: Vec<PathBuf> = fs::read_dir(dir)
|
||||
.unwrap()
|
||||
.map(|f| f.unwrap().path())
|
||||
.filter(|f| ["jpg", "heic"].contains(&f.extension().unwrap().to_ascii_lowercase().to_str().unwrap()))
|
||||
.filter(is_image)
|
||||
.collect();
|
||||
files.sort();
|
||||
files
|
||||
@ -124,7 +126,35 @@ pub fn get_embedded_thumbnail(path: PathBuf) -> Option<Vec<u8>> {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_image(path: &PathBuf) -> bool {
|
||||
if !path.is_file() {
|
||||
return false;
|
||||
}
|
||||
["jpg", "heic", "heif"].contains(
|
||||
&path
|
||||
.extension()
|
||||
.unwrap()
|
||||
.to_ascii_lowercase()
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
fn is_heif(path: &PathBuf) -> bool {
|
||||
["heif", "heic"].contains(
|
||||
&path
|
||||
.extension()
|
||||
.unwrap()
|
||||
.to_ascii_lowercase()
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn load_thumbnail(path: &PathBuf) -> ImflowImageBuffer {
|
||||
if is_heif(path) {
|
||||
return load_heif(path, true);
|
||||
}
|
||||
match load_thumbnail_exif(path) {
|
||||
Some(thumbnail) => return thumbnail,
|
||||
None => load_thumbnail_full(path),
|
||||
@ -141,22 +171,22 @@ pub fn load_thumbnail_exif(path: &PathBuf) -> Option<ImflowImageBuffer> {
|
||||
|
||||
let width: usize = image.width() as usize;
|
||||
let height: usize = image.height() as usize;
|
||||
let mut flat = image.into_rgba8().into_raw();
|
||||
let mut buffer: Vec<u32> = vec![0; width * height];
|
||||
|
||||
for (rgba, argb) in flat.chunks_mut(4).zip(buffer.iter_mut()) {
|
||||
let r = rgba[0] as u32;
|
||||
let g = rgba[1] as u32;
|
||||
let b = rgba[2] as u32;
|
||||
*argb = r << 16 | g << 8 | b;
|
||||
}
|
||||
let flat = image.into_rgba8().into_raw();
|
||||
let mut buffer = flat.to_vec();
|
||||
let buffer_u32 = unsafe {
|
||||
Vec::from_raw_parts(
|
||||
buffer.as_mut_ptr() as *mut u32,
|
||||
buffer.len() / 4,
|
||||
buffer.len() / 4,
|
||||
)
|
||||
};
|
||||
|
||||
let rating = get_rating(path.into());
|
||||
|
||||
Some(ImflowImageBuffer {
|
||||
width,
|
||||
height,
|
||||
argb_buffer: buffer,
|
||||
rgba_buffer: buffer_u32,
|
||||
rating,
|
||||
})
|
||||
}
|
||||
@ -175,13 +205,66 @@ pub fn load_thumbnail_full(path: &PathBuf) -> ImflowImageBuffer {
|
||||
.resize(640, 480, FilterType::Nearest);
|
||||
let width = image.width() as usize;
|
||||
let height = image.height() as usize;
|
||||
let buffer = image_to_argb_buffer(image);
|
||||
let buffer = image_to_rgba_buffer(image);
|
||||
let rating = get_rating(path.into());
|
||||
|
||||
ImflowImageBuffer {
|
||||
width,
|
||||
height,
|
||||
argb_buffer: buffer,
|
||||
rgba_buffer: buffer,
|
||||
rating,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_heif(path: &PathBuf, resize: bool) -> ImflowImageBuffer {
|
||||
let lib_heif = LibHeif::new();
|
||||
let ctx = HeifContext::read_from_file(path.to_str().unwrap()).unwrap();
|
||||
let handle = ctx.primary_image_handle().unwrap();
|
||||
// assert_eq!(handle.width(), 1652);
|
||||
// assert_eq!(handle.height(), 1791);
|
||||
|
||||
// Get Exif
|
||||
// let mut meta_ids: Vec<ItemId> = vec![0; 1];
|
||||
// let count = handle.metadata_block_ids(&mut meta_ids, b"Exif");
|
||||
// assert_eq!(count, 1);
|
||||
// let exif: Vec<u8> = handle.metadata(meta_ids[0]).unwrap();
|
||||
|
||||
// Decode the image
|
||||
let mut image = lib_heif
|
||||
.decode(&handle, libheif_rs::ColorSpace::Rgb(RgbChroma::Rgba), None)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
image.color_space(),
|
||||
Some(libheif_rs::ColorSpace::Rgb(RgbChroma::Rgba)),
|
||||
);
|
||||
|
||||
// Scale the image
|
||||
if resize {
|
||||
image = image.scale(640, 480, None).unwrap();
|
||||
assert_eq!(image.width(), 640);
|
||||
assert_eq!(image.height(), 480);
|
||||
}
|
||||
|
||||
let width = image.width() as usize;
|
||||
let height = image.height() as usize;
|
||||
let rating = get_rating(path);
|
||||
|
||||
// Get "pixels"
|
||||
let planes = image.planes();
|
||||
let interleaved_plane = planes.interleaved.unwrap();
|
||||
assert!(!interleaved_plane.data.is_empty());
|
||||
assert!(interleaved_plane.stride > 0);
|
||||
|
||||
let rgba_buffer = interleaved_plane.data;
|
||||
// Create a slice of u32 from the u8 slice
|
||||
let u32_slice = unsafe {
|
||||
std::slice::from_raw_parts(rgba_buffer.as_ptr() as *const u32, rgba_buffer.len() / 4)
|
||||
};
|
||||
|
||||
ImflowImageBuffer {
|
||||
width,
|
||||
height,
|
||||
rgba_buffer: u32_slice.to_vec(),
|
||||
rating,
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
struct Transforms {
|
||||
transform: mat4x4<f32>,
|
||||
width: u32,
|
||||
height: u32
|
||||
};
|
||||
@group(0) @binding(2) var<uniform> transforms: Transforms;
|
||||
|
||||
@ -16,7 +18,6 @@ struct VertexOutput {
|
||||
@vertex
|
||||
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
// Apply zoom/transformation matrix
|
||||
out.position = transforms.transform * vec4<f32>(in.position, 1.0);
|
||||
out.uv = in.uv;
|
||||
return out;
|
||||
@ -27,5 +28,9 @@ fn vs_main(in: VertexInput) -> VertexOutput {
|
||||
|
||||
@fragment
|
||||
fn fs_main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
|
||||
return textureSample(texture, texture_sampler, uv);
|
||||
let texture_size = vec2<f32>(f32(transforms.width), f32(transforms.height));
|
||||
let out_dim = vec2<f32>(textureDimensions(texture));
|
||||
let scale = texture_size / out_dim;
|
||||
let pixel = uv * scale;
|
||||
return textureSample(texture, texture_sampler, pixel);
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ impl ImageStore {
|
||||
);
|
||||
|
||||
let path = available_images[0].clone();
|
||||
let image = load_image(path.clone());
|
||||
let image = load_image(&path.clone());
|
||||
loaded_images.insert(path, image);
|
||||
let mut state = Self {
|
||||
current_image_id,
|
||||
@ -91,7 +91,7 @@ impl ImageStore {
|
||||
|
||||
pub fn get_current_rating(&self) -> i32 {
|
||||
let imbuf = if let Some(full) = self.get_current_image() {
|
||||
println!("full");
|
||||
// println!("full");
|
||||
full
|
||||
} else {
|
||||
// TODO: this assumes loaded thumbnail
|
||||
@ -122,7 +122,7 @@ impl ImageStore {
|
||||
self.currently_loading.insert(path.clone());
|
||||
|
||||
self.pool.execute(move || {
|
||||
let image = load_image(path.clone());
|
||||
let image = load_image(&path.clone());
|
||||
let _ = tx.send((path, image));
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user