From afc6b4dee886a65caa9cfd355ed08aed8ac3e7ce Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 21 Apr 2024 15:57:00 +0200 Subject: [PATCH 01/29] Adding a wrapper struct for Texture which will be extended to hold an array of textures for big images --- src/appstate.rs | 26 +++++++++++++++++++++++++- src/main.rs | 23 +++++++++++------------ src/ui.rs | 6 +++--- src/utils.rs | 13 +++++++++---- 4 files changed, 48 insertions(+), 20 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index 66f971b6..d1673df8 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -43,6 +43,30 @@ impl Message { } } +pub struct TexWrap{ + pub tex:Texture, + pub size_vec:(f32,f32) // Will be the whole Texture Array size soon +} + +impl TexWrap{ + pub fn new(texture: Texture) -> Self{ + let s = texture.size(); + TexWrap { tex: texture, size_vec:s } + } + + pub fn size(&self)->(f32,f32){ + return self.size_vec; + } + + pub fn width(&self)-> f32 { + return self.size_vec.0; + } + + pub fn height(&self)-> f32 { + return self.size_vec.1; + } +} + /// The state of the application #[derive(AppState)] pub struct OculanteState { @@ -65,7 +89,7 @@ pub struct OculanteState { pub extended_info_loading: bool, /// The Player, responsible for loading and sending Frames pub player: Player, - pub current_texture: Option, + pub current_texture: Option, pub current_path: Option, pub current_image: Option, pub settings_enabled: bool, diff --git a/src/main.rs b/src/main.rs index 9eafaf88..5b817448 100644 --- a/src/main.rs +++ b/src/main.rs @@ -894,13 +894,12 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O state.redraw = false; } } - + if let Some(tex) = &mut state.current_texture { if tex.width() as u32 == img.width() && tex.height() as u32 == img.height() { - img.update_texture(gfx, tex); - } else { - state.current_texture = - img.to_texture(gfx, state.persistent_settings.linear_mag_filter); + img.update_texture(gfx, & mut tex.tex); //TODO: Kachel-Update + } else { + state.current_texture = img.to_texture(gfx, state.persistent_settings.linear_mag_filter); } } else { debug!("Setting texture"); @@ -1079,22 +1078,22 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O } } if state.tiling < 2 { - draw.image(texture) + draw.image(&texture.tex) .blend_mode(BlendMode::NORMAL) .scale(state.image_geometry.scale, state.image_geometry.scale) .translate(state.image_geometry.offset.x, state.image_geometry.offset.y); } else { - draw.pattern(texture) + draw.pattern(&texture.tex) .scale(state.image_geometry.scale, state.image_geometry.scale) .translate(state.image_geometry.offset.x, state.image_geometry.offset.y) .size( - texture.width() * state.tiling as f32, - texture.height() * state.tiling as f32, + texture.tex.width() * state.tiling as f32, + texture.tex.height() * state.tiling as f32, ); } if state.persistent_settings.show_frame { - draw.rect((0.0, 0.0), texture.size()) + draw.rect((0.0, 0.0), texture.tex.size()) .stroke(1.0) .color(Color { r: 0.5, @@ -1117,7 +1116,7 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O > app.window().size().0 as f32; if show_minimap { - draw.image(texture) + draw.image(&texture.tex) .blend_mode(BlendMode::NORMAL) .translate(offset_x, 100.) .scale(scale, scale); @@ -1127,7 +1126,7 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O // Draw a brush preview when paint mode is on if state.edit_state.painting { if let Some(stroke) = state.edit_state.paint_strokes.last() { - let dim = texture.width().min(texture.height()) / 50.; + let dim = texture.tex.width().min(texture.tex.height()) / 50.; draw.circle(20.) // .translate(state.cursor_relative.x, state.cursor_relative.y) .alpha(0.5) diff --git a/src/ui.rs b/src/ui.rs index f8e501d5..407b2622 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -183,7 +183,7 @@ impl EguiExt for Ui { #[allow(unused)] pub fn image_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { if let Some(texture) = &state.current_texture { - let tex_id = gfx.egui_register_texture(texture); + let tex_id = gfx.egui_register_texture(&texture.tex); let image_rect = Rect::from_center_size( Pos2::new( @@ -248,7 +248,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { .show(ui, |ui| { if let Some(texture) = &state.current_texture { // texture. - let tex_id = gfx.egui_register_texture(texture); + let tex_id = gfx.egui_register_texture(&texture.tex); // width of image widget // let desired_width = ui.available_width() - ui.spacing().indent; @@ -1105,7 +1105,7 @@ pub fn edit_ui(app: &mut App, ctx: &Context, state: &mut OculanteState, gfx: &mu if tex.width() as u32 == state.edit_state.result_pixel_op.width() && state.edit_state.result_pixel_op.height() == img.height() { - state.edit_state.result_pixel_op.update_texture(gfx, tex); + state.edit_state.result_pixel_op.update_texture(gfx, & mut tex.tex); } else { state.current_texture = state.edit_state.result_pixel_op.to_texture(gfx, state.persistent_settings.linear_mag_filter); diff --git a/src/utils.rs b/src/utils.rs index 5734390e..e16d3dbb 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -29,6 +29,7 @@ use crate::cache::Cache; use crate::image_editing::{self, ImageOperation}; use crate::image_loader::open_image; use crate::shortcuts::{lookup, InputEvent, Shortcuts}; +use crate::TexWrap; pub const SUPPORTED_EXTENSIONS: &[&str] = &[ "bmp", @@ -608,7 +609,7 @@ pub trait ImageExt { unimplemented!() } - fn to_texture(&self, _: &mut Graphics, _linear_mag_filter: bool) -> Option { + fn to_texture(&self, _: &mut Graphics, _linear_mag_filter: bool) -> Option { unimplemented!() } @@ -630,8 +631,8 @@ impl ImageExt for RgbaImage { Vector2::new(self.width() as f32, self.height() as f32) } - fn to_texture(&self, gfx: &mut Graphics, linear_mag_filter: bool) -> Option { - gfx.create_texture() + fn to_texture(&self, gfx: &mut Graphics, linear_mag_filter: bool) -> Option { + let tex = gfx.create_texture() .from_bytes(self, self.width(), self.height()) .with_mipmaps(true) // .with_format(notan::prelude::TextureFormat::SRgba8) @@ -646,7 +647,11 @@ impl ImageExt for RgbaImage { ) // .with_wrap(TextureWrap::Clamp, TextureWrap::Clamp) .build() - .ok() + .ok(); + match tex { + None => None, + Some(t) => Some(TexWrap::new(t)), + } } fn to_texture_premult(&self, gfx: &mut Graphics) -> Option { From 06eb55b3326eb95e521a12ae30ddffb4f8f4ebe7 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 21 Apr 2024 20:24:23 +0200 Subject: [PATCH 02/29] Adding image slicing (still only displaying the first slice, wip) --- src/appstate.rs | 108 ++++++++++++++++++++++++++++++++++++++++++++++-- src/main.rs | 16 +++---- src/ui.rs | 6 +-- src/utils.rs | 15 ++++--- 4 files changed, 125 insertions(+), 20 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index d1673df8..dca6fccf 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -2,12 +2,14 @@ use crate::{ image_editing::EditState, scrubber::Scrubber, settings::PersistentSettings, - utils::{ExtendedImageInfo, Frame, Player}, + utils::{ExtendedImageInfo, Frame, Player}, ImageExt, }; use egui_notify::Toasts; use image::RgbaImage; +use image::imageops; use nalgebra::Vector2; use notan::{egui::epaint::ahash::HashMap, prelude::Texture, AppState}; +use notan::prelude::{Graphics, TextureFilter}; use std::{ path::PathBuf, sync::mpsc::{self, Receiver, Sender}, @@ -44,14 +46,114 @@ impl Message { } pub struct TexWrap{ - pub tex:Texture, + //pub tex:Texture, + pub texor:Vec, + //pub asbet:Option, + pub col_count:u32, + pub row_count:u32, + pub col_translation:u32, + pub row_translation:u32, pub size_vec:(f32,f32) // Will be the whole Texture Array size soon } impl TexWrap{ - pub fn new(texture: Texture) -> Self{ + /*pub fn new(texture: Texture) -> Self{ let s = texture.size(); TexWrap { tex: texture, size_vec:s } + }*/ + + pub fn from_rgbaimage(gfx: &mut Graphics, linear_mag_filter: bool, image: &RgbaImage) -> Option{ + let im_w = image.width(); + let im_h = image.height(); + let s = (im_w as f32, im_h as f32); + let max_texture_size = gfx.limits().max_texture_size; + let col_count = (im_w as f32/max_texture_size as f32).ceil() as u32; + let row_count = (im_h as f32/max_texture_size as f32).ceil() as u32; + + + + let mut a:Vec = Vec::new(); + let row_increment = std::cmp::min(max_texture_size, im_h); + let col_increment = std::cmp::min(max_texture_size, im_w); + let mut fine = true; + + for row_index in 0..row_count { + let tex_start_y = row_index*row_increment; + let tex_height = std::cmp::min( + row_increment, + im_h-tex_start_y + ); + for col_index in 0..col_count { + let tex_start_x = col_index*col_increment; + let tex_width = std::cmp::min( + col_increment, + im_w-tex_start_x + ); + print!("{0},{1},{2},{3}",tex_start_y, tex_height, tex_start_x, tex_width); + let sub_img = imageops::crop_imm(image, tex_start_x, tex_start_y, tex_width, tex_height); + let my_img = sub_img.to_image(); + let tex = gfx.create_texture() + .from_bytes(my_img.as_ref(), my_img.width(), my_img.height()) + .with_mipmaps(true) + // .with_format(notan::prelude::TextureFormat::SRgba8) + // .with_premultiplied_alpha() + .with_filter( + TextureFilter::Linear, + if linear_mag_filter { + TextureFilter::Linear + } else { + TextureFilter::Nearest + }, + ) + // .with_wrap(TextureWrap::Clamp, TextureWrap::Clamp) + .build() + .ok(); + + + if let Some(t) = tex { + a.push(t); + } + else{ + fine = false; + break; + } + } + if(fine == false){ + break; + } + } + + /*let sub_img = imageops::crop_imm(image, 0, 0, max_texture_size, image.height()); + let my_img = sub_img.to_image(); + let tex = gfx.create_texture() + .from_bytes(my_img.as_ref(), my_img.width(), my_img.height()) + .with_mipmaps(true) + // .with_format(notan::prelude::TextureFormat::SRgba8) + // .with_premultiplied_alpha() + .with_filter( + TextureFilter::Linear, + if linear_mag_filter { + TextureFilter::Linear + } else { + TextureFilter::Nearest + }, + ) + // .with_wrap(TextureWrap::Clamp, TextureWrap::Clamp) + .build() + .ok(); + + match tex { + None => None, + Some(t) => Some(TexWrap { tex: t, size_vec:s, col_count:col_count, row_count:row_count }), + }*/ + + if(fine){ + Some(TexWrap {size_vec:s, col_count:col_count, row_count:row_count,texor:a, col_translation:col_increment, row_translation:row_increment }) + } + else { + None + } + } pub fn size(&self)->(f32,f32){ diff --git a/src/main.rs b/src/main.rs index 5b817448..ecdddd46 100644 --- a/src/main.rs +++ b/src/main.rs @@ -897,7 +897,7 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O if let Some(tex) = &mut state.current_texture { if tex.width() as u32 == img.width() && tex.height() as u32 == img.height() { - img.update_texture(gfx, & mut tex.tex); //TODO: Kachel-Update + img.update_texture(gfx, & mut tex.texor[0]); //TODO: Kachel-Update } else { state.current_texture = img.to_texture(gfx, state.persistent_settings.linear_mag_filter); } @@ -1078,22 +1078,22 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O } } if state.tiling < 2 { - draw.image(&texture.tex) + draw.image(&texture.texor[0]) .blend_mode(BlendMode::NORMAL) .scale(state.image_geometry.scale, state.image_geometry.scale) .translate(state.image_geometry.offset.x, state.image_geometry.offset.y); } else { - draw.pattern(&texture.tex) + draw.pattern(&texture.texor[0]) .scale(state.image_geometry.scale, state.image_geometry.scale) .translate(state.image_geometry.offset.x, state.image_geometry.offset.y) .size( - texture.tex.width() * state.tiling as f32, - texture.tex.height() * state.tiling as f32, + texture.texor[0].width() * state.tiling as f32, + texture.texor[0].height() * state.tiling as f32, ); } if state.persistent_settings.show_frame { - draw.rect((0.0, 0.0), texture.tex.size()) + draw.rect((0.0, 0.0), texture.texor[0].size()) .stroke(1.0) .color(Color { r: 0.5, @@ -1116,7 +1116,7 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O > app.window().size().0 as f32; if show_minimap { - draw.image(&texture.tex) + draw.image(&texture.texor[0]) .blend_mode(BlendMode::NORMAL) .translate(offset_x, 100.) .scale(scale, scale); @@ -1126,7 +1126,7 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O // Draw a brush preview when paint mode is on if state.edit_state.painting { if let Some(stroke) = state.edit_state.paint_strokes.last() { - let dim = texture.tex.width().min(texture.tex.height()) / 50.; + let dim = texture.texor[0].width().min(texture.texor[0].height()) / 50.; draw.circle(20.) // .translate(state.cursor_relative.x, state.cursor_relative.y) .alpha(0.5) diff --git a/src/ui.rs b/src/ui.rs index 407b2622..d15e0fe3 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -183,7 +183,7 @@ impl EguiExt for Ui { #[allow(unused)] pub fn image_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { if let Some(texture) = &state.current_texture { - let tex_id = gfx.egui_register_texture(&texture.tex); + let tex_id = gfx.egui_register_texture(&texture.texor[0]); let image_rect = Rect::from_center_size( Pos2::new( @@ -248,7 +248,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { .show(ui, |ui| { if let Some(texture) = &state.current_texture { // texture. - let tex_id = gfx.egui_register_texture(&texture.tex); + let tex_id = gfx.egui_register_texture(&texture.texor[0]); // width of image widget // let desired_width = ui.available_width() - ui.spacing().indent; @@ -1105,7 +1105,7 @@ pub fn edit_ui(app: &mut App, ctx: &Context, state: &mut OculanteState, gfx: &mu if tex.width() as u32 == state.edit_state.result_pixel_op.width() && state.edit_state.result_pixel_op.height() == img.height() { - state.edit_state.result_pixel_op.update_texture(gfx, & mut tex.tex); + state.edit_state.result_pixel_op.update_texture(gfx, & mut tex.texor[0]); } else { state.current_texture = state.edit_state.result_pixel_op.to_texture(gfx, state.persistent_settings.linear_mag_filter); diff --git a/src/utils.rs b/src/utils.rs index e16d3dbb..316ad72f 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -288,6 +288,8 @@ pub fn send_image_threaded( // .clone() // .send(Frame::new_reset(f.buffer.clone())); + let cheat_max_texture_size:u32 = 65384; + let mut first = true; for mut f in frame_receiver.iter() { if let Some(ref fs) = forced_frame_source { @@ -304,15 +306,15 @@ pub fn send_image_threaded( let largest_side = f.buffer.dimensions().0.max(f.buffer.dimensions().1); // Check if texture is too large to fit on the texture - if largest_side > max_texture_size { + if largest_side > cheat_max_texture_size { _ = message_sender.send(Message::warn("This image exceeded the maximum resolution and will be be scaled down.")); - let scale_factor = max_texture_size as f32 / largest_side as f32; + let scale_factor = cheat_max_texture_size as f32 / largest_side as f32; let new_dimensions = ( (f.buffer.dimensions().0 as f32 * scale_factor) - .min(max_texture_size as f32) + .min(cheat_max_texture_size as f32) as u32, (f.buffer.dimensions().1 as f32 * scale_factor) - .min(max_texture_size as f32) + .min(cheat_max_texture_size as f32) as u32, ); @@ -632,7 +634,7 @@ impl ImageExt for RgbaImage { } fn to_texture(&self, gfx: &mut Graphics, linear_mag_filter: bool) -> Option { - let tex = gfx.create_texture() + /*let tex = gfx.create_texture() .from_bytes(self, self.width(), self.height()) .with_mipmaps(true) // .with_format(notan::prelude::TextureFormat::SRgba8) @@ -651,7 +653,8 @@ impl ImageExt for RgbaImage { match tex { None => None, Some(t) => Some(TexWrap::new(t)), - } + }*/ + TexWrap::from_rgbaimage(gfx, linear_mag_filter, self) } fn to_texture_premult(&self, gfx: &mut Graphics) -> Option { From ff5790c12ff9b58b87a21036a832e5763cd3a31f Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 21 Apr 2024 20:51:21 +0200 Subject: [PATCH 03/29] Adding drawing of sliced images (missing: texture update, drawing, ...) --- src/appstate.rs | 8 +++----- src/main.rs | 35 +++++++++++++++++++++++------------ src/ui.rs | 6 +++--- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index dca6fccf..3ec6eee0 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -46,14 +46,12 @@ impl Message { } pub struct TexWrap{ - //pub tex:Texture, - pub texor:Vec, - //pub asbet:Option, + pub texture_array:Vec, pub col_count:u32, pub row_count:u32, pub col_translation:u32, pub row_translation:u32, - pub size_vec:(f32,f32) // Will be the whole Texture Array size soon + pub size_vec:(f32,f32) // The whole Texture Array size } impl TexWrap{ @@ -148,7 +146,7 @@ impl TexWrap{ }*/ if(fine){ - Some(TexWrap {size_vec:s, col_count:col_count, row_count:row_count,texor:a, col_translation:col_increment, row_translation:row_increment }) + Some(TexWrap {size_vec:s, col_count:col_count, row_count:row_count,texture_array:a, col_translation:col_increment, row_translation:row_increment }) } else { None diff --git a/src/main.rs b/src/main.rs index ecdddd46..16aae491 100644 --- a/src/main.rs +++ b/src/main.rs @@ -897,7 +897,7 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O if let Some(tex) = &mut state.current_texture { if tex.width() as u32 == img.width() && tex.height() as u32 == img.height() { - img.update_texture(gfx, & mut tex.texor[0]); //TODO: Kachel-Update + img.update_texture(gfx, & mut tex.texture_array[0]); //TODO: Kachel-Update } else { state.current_texture = img.to_texture(gfx, state.persistent_settings.linear_mag_filter); } @@ -1078,22 +1078,33 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O } } if state.tiling < 2 { - draw.image(&texture.texor[0]) - .blend_mode(BlendMode::NORMAL) - .scale(state.image_geometry.scale, state.image_geometry.scale) - .translate(state.image_geometry.offset.x, state.image_geometry.offset.y); + let mut tex_idx = 0; + for row_idx in 0..texture.row_count + { + let translate_y = state.image_geometry.offset.y+state.image_geometry.scale*row_idx as f32*texture.row_translation as f32; + for col_idx in 0..texture.col_count + { + let translate_x = state.image_geometry.offset.x+state.image_geometry.scale*col_idx as f32 *texture.col_translation as f32; + draw.image(&texture.texture_array[tex_idx]) + .blend_mode(BlendMode::NORMAL) + .scale(state.image_geometry.scale, state.image_geometry.scale) + .translate(translate_x, translate_y); + tex_idx += 1; + } + } } else { - draw.pattern(&texture.texor[0]) + //TODO: How to implement this efficient? + draw.pattern(&texture.texture_array[0]) .scale(state.image_geometry.scale, state.image_geometry.scale) .translate(state.image_geometry.offset.x, state.image_geometry.offset.y) .size( - texture.texor[0].width() * state.tiling as f32, - texture.texor[0].height() * state.tiling as f32, + texture.texture_array[0].width() * state.tiling as f32, + texture.texture_array[0].height() * state.tiling as f32, ); } if state.persistent_settings.show_frame { - draw.rect((0.0, 0.0), texture.texor[0].size()) + draw.rect((0.0, 0.0), texture.size()) .stroke(1.0) .color(Color { r: 0.5, @@ -1115,8 +1126,8 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O * state.image_geometry.scale > app.window().size().0 as f32; - if show_minimap { - draw.image(&texture.texor[0]) + if show_minimap { //TODO! + draw.image(&texture.texture_array[0]) .blend_mode(BlendMode::NORMAL) .translate(offset_x, 100.) .scale(scale, scale); @@ -1126,7 +1137,7 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O // Draw a brush preview when paint mode is on if state.edit_state.painting { if let Some(stroke) = state.edit_state.paint_strokes.last() { - let dim = texture.texor[0].width().min(texture.texor[0].height()) / 50.; + let dim = texture.width().min(texture.height()) / 50.; draw.circle(20.) // .translate(state.cursor_relative.x, state.cursor_relative.y) .alpha(0.5) diff --git a/src/ui.rs b/src/ui.rs index d15e0fe3..8cfe35aa 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -183,7 +183,7 @@ impl EguiExt for Ui { #[allow(unused)] pub fn image_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { if let Some(texture) = &state.current_texture { - let tex_id = gfx.egui_register_texture(&texture.texor[0]); + let tex_id = gfx.egui_register_texture(&texture.texture_array[0]); //TODO: Adapt if needed let image_rect = Rect::from_center_size( Pos2::new( @@ -248,7 +248,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { .show(ui, |ui| { if let Some(texture) = &state.current_texture { // texture. - let tex_id = gfx.egui_register_texture(&texture.texor[0]); + let tex_id = gfx.egui_register_texture(&texture.texture_array[0]); // width of image widget // let desired_width = ui.available_width() - ui.spacing().indent; @@ -1105,7 +1105,7 @@ pub fn edit_ui(app: &mut App, ctx: &Context, state: &mut OculanteState, gfx: &mu if tex.width() as u32 == state.edit_state.result_pixel_op.width() && state.edit_state.result_pixel_op.height() == img.height() { - state.edit_state.result_pixel_op.update_texture(gfx, & mut tex.texor[0]); + state.edit_state.result_pixel_op.update_texture(gfx, & mut tex.texture_array[0]); //TODO! } else { state.current_texture = state.edit_state.result_pixel_op.to_texture(gfx, state.persistent_settings.linear_mag_filter); From d82c016d61937d65659fdce8a3dc319aa59841f7 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 22 Apr 2024 20:42:11 +0200 Subject: [PATCH 04/29] Updating texture --- src/appstate.rs | 144 ++++++++++++++++++++++++++++++++++-------------- src/main.rs | 2 +- src/ui.rs | 2 +- src/utils.rs | 32 ++++------- 4 files changed, 116 insertions(+), 64 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index 3ec6eee0..e841e481 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -14,6 +14,7 @@ use std::{ path::PathBuf, sync::mpsc::{self, Receiver, Sender}, }; +use log::error; #[derive(Debug, Clone)] pub struct ImageGeometry { @@ -60,7 +61,58 @@ impl TexWrap{ TexWrap { tex: texture, size_vec:s } }*/ + //pub fn from_rgba_image_premult(gfx: &mut Graphics, linear_mag_filter: bool, image: &RgbaImage) -> Option{} + pub fn from_rgbaimage(gfx: &mut Graphics, linear_mag_filter: bool, image: &RgbaImage) -> Option{ + Self::gen_from_rgbaimage(gfx, linear_mag_filter, image, Self::gen_texture_standard) + } + + pub fn from_rgbaimage_premult(gfx: &mut Graphics, linear_mag_filter: bool, image: &RgbaImage) -> Option{ + Self::gen_from_rgbaimage(gfx, linear_mag_filter, image, Self::gen_texture_premult) + } + + fn gen_texture_standard(gfx: &mut Graphics, bytes:&[u8], width:u32, height:u32, linear_mag_filter:bool)-> Option + { + gfx.create_texture() + .from_bytes(bytes, width, height) + .with_mipmaps(true) + // .with_format(notan::prelude::TextureFormat::SRgba8) + // .with_premultiplied_alpha() + .with_filter( + TextureFilter::Linear, + if linear_mag_filter { + TextureFilter::Linear + } else { + TextureFilter::Nearest + }, + ) + // .with_wrap(TextureWrap::Clamp, TextureWrap::Clamp) + .build() + .ok() + } + + fn gen_texture_premult(gfx: &mut Graphics, bytes:&[u8], width:u32, height:u32, linear_mag_filter:bool)-> Option + { + gfx.create_texture() + .from_bytes(bytes, width, height) + .with_premultiplied_alpha() + .with_mipmaps(true) + // .with_format(notan::prelude::TextureFormat::SRgba8) + // .with_premultiplied_alpha() + .with_filter( + TextureFilter::Linear, + if linear_mag_filter { + TextureFilter::Linear + } else { + TextureFilter::Nearest + }, + ) + // .with_wrap(TextureWrap::Clamp, TextureWrap::Clamp) + .build() + .ok() + } + + fn gen_from_rgbaimage(gfx: &mut Graphics, linear_mag_filter: bool, image: &RgbaImage, fuuun: fn (&mut Graphics, &[u8], u32, u32, bool)-> Option) -> Option{ let im_w = image.width(); let im_h = image.height(); let s = (im_w as f32, im_h as f32); @@ -90,24 +142,8 @@ impl TexWrap{ print!("{0},{1},{2},{3}",tex_start_y, tex_height, tex_start_x, tex_width); let sub_img = imageops::crop_imm(image, tex_start_x, tex_start_y, tex_width, tex_height); let my_img = sub_img.to_image(); - let tex = gfx.create_texture() - .from_bytes(my_img.as_ref(), my_img.width(), my_img.height()) - .with_mipmaps(true) - // .with_format(notan::prelude::TextureFormat::SRgba8) - // .with_premultiplied_alpha() - .with_filter( - TextureFilter::Linear, - if linear_mag_filter { - TextureFilter::Linear - } else { - TextureFilter::Nearest - }, - ) - // .with_wrap(TextureWrap::Clamp, TextureWrap::Clamp) - .build() - .ok(); + let tex = fuuun(gfx, my_img.as_ref(), my_img.width(), my_img.height(), linear_mag_filter); - if let Some(t) = tex { a.push(t); } @@ -121,37 +157,43 @@ impl TexWrap{ } } - /*let sub_img = imageops::crop_imm(image, 0, 0, max_texture_size, image.height()); - let my_img = sub_img.to_image(); - let tex = gfx.create_texture() - .from_bytes(my_img.as_ref(), my_img.width(), my_img.height()) - .with_mipmaps(true) - // .with_format(notan::prelude::TextureFormat::SRgba8) - // .with_premultiplied_alpha() - .with_filter( - TextureFilter::Linear, - if linear_mag_filter { - TextureFilter::Linear - } else { - TextureFilter::Nearest - }, - ) - // .with_wrap(TextureWrap::Clamp, TextureWrap::Clamp) - .build() - .ok(); - - match tex { - None => None, - Some(t) => Some(TexWrap { tex: t, size_vec:s, col_count:col_count, row_count:row_count }), - }*/ - if(fine){ Some(TexWrap {size_vec:s, col_count:col_count, row_count:row_count,texture_array:a, col_translation:col_increment, row_translation:row_increment }) } else { None } + } + pub fn update_textures(&mut self, gfx: &mut Graphics, image: &RgbaImage){ + if(self.col_count==1 && self.row_count==1){ + if let Err(e) = gfx.update_texture(&mut self.texture_array[0]).with_data(image).update() { + error!("{e}"); + } + }else{ + let mut tex_index = 0; + for row_index in 0..self.row_count { + let tex_start_y = row_index*self.row_translation; + let tex_height = std::cmp::min( + self.row_translation, + image.height()-tex_start_y + ); + for col_index in 0..self.col_count { + let tex_start_x = col_index*self.col_translation; + let tex_width = std::cmp::min( + self.col_translation, + image.width()-tex_start_x + ); + print!("{0},{1},{2},{3}",tex_start_y, tex_height, tex_start_x, tex_width); + let sub_img = imageops::crop_imm(image, tex_start_x, tex_start_y, tex_width, tex_height); + let my_img = sub_img.to_image(); + if let Err(e) = gfx.update_texture(&mut self.texture_array[tex_index]).with_data(my_img.as_ref()).update() { + error!("{e}"); + } + tex_index += 1; + } + } + } } pub fn size(&self)->(f32,f32){ @@ -167,6 +209,26 @@ impl TexWrap{ } } +// Implement `Iterator` for `Fibonacci`. +// The `Iterator` trait only requires a method to be defined for the `next` element. +/*impl Iterator for TexWrap { + // We can refer to this type using Self::Item + type Item = (u32,u32, Texture); + + // Here, we define the sequence using `.curr` and `.next`. + // The return type is `Option`: + // * When the `Iterator` is finished, `None` is returned. + // * Otherwise, the next value is wrapped in `Some` and returned. + // We use Self::Item in the return type, so we can change + // the type without having to update the function signatures. + fn next(&mut self) -> Option { + + self.index +=1; + + None + } +}*/ + /// The state of the application #[derive(AppState)] pub struct OculanteState { diff --git a/src/main.rs b/src/main.rs index 16aae491..223cc93d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -897,7 +897,7 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O if let Some(tex) = &mut state.current_texture { if tex.width() as u32 == img.width() && tex.height() as u32 == img.height() { - img.update_texture(gfx, & mut tex.texture_array[0]); //TODO: Kachel-Update + img.update_texture_with_texwrap(gfx, tex); //TODO: Kachel-Update } else { state.current_texture = img.to_texture(gfx, state.persistent_settings.linear_mag_filter); } diff --git a/src/ui.rs b/src/ui.rs index 8cfe35aa..e2d40334 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1105,7 +1105,7 @@ pub fn edit_ui(app: &mut App, ctx: &Context, state: &mut OculanteState, gfx: &mu if tex.width() as u32 == state.edit_state.result_pixel_op.width() && state.edit_state.result_pixel_op.height() == img.height() { - state.edit_state.result_pixel_op.update_texture(gfx, & mut tex.texture_array[0]); //TODO! + state.edit_state.result_pixel_op.update_texture_with_texwrap(gfx, tex); //TODO! } else { state.current_texture = state.edit_state.result_pixel_op.to_texture(gfx, state.persistent_settings.linear_mag_filter); diff --git a/src/utils.rs b/src/utils.rs index 316ad72f..94896984 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -31,6 +31,8 @@ use crate::image_loader::open_image; use crate::shortcuts::{lookup, InputEvent, Shortcuts}; use crate::TexWrap; +use crate::utils::image::imageops; + pub const SUPPORTED_EXTENSIONS: &[&str] = &[ "bmp", "dds", @@ -623,6 +625,10 @@ pub trait ImageExt { unimplemented!() } + fn update_texture_with_texwrap(&self, _: &mut Graphics, _: &mut TexWrap) { + unimplemented!() + } + fn to_image(&self, _: &mut Graphics) -> Option { unimplemented!() } @@ -633,27 +639,7 @@ impl ImageExt for RgbaImage { Vector2::new(self.width() as f32, self.height() as f32) } - fn to_texture(&self, gfx: &mut Graphics, linear_mag_filter: bool) -> Option { - /*let tex = gfx.create_texture() - .from_bytes(self, self.width(), self.height()) - .with_mipmaps(true) - // .with_format(notan::prelude::TextureFormat::SRgba8) - // .with_premultiplied_alpha() - .with_filter( - TextureFilter::Linear, - if linear_mag_filter { - TextureFilter::Linear - } else { - TextureFilter::Nearest - }, - ) - // .with_wrap(TextureWrap::Clamp, TextureWrap::Clamp) - .build() - .ok(); - match tex { - None => None, - Some(t) => Some(TexWrap::new(t)), - }*/ + fn to_texture(&self, gfx: &mut Graphics, linear_mag_filter: bool) -> Option { TexWrap::from_rgbaimage(gfx, linear_mag_filter, self) } @@ -672,6 +658,10 @@ impl ImageExt for RgbaImage { error!("{e}"); } } + + fn update_texture_with_texwrap(&self, gfx: &mut Graphics, texture: &mut TexWrap) { + texture.update_textures(gfx,self); + } } impl ImageExt for (i32, i32) { From 1ebd52e3cf15365bf1925619b78a5eac008deaae Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 22 Apr 2024 21:41:42 +0200 Subject: [PATCH 05/29] Moving tiled texture drawing to texture wrapper --- src/appstate.rs | 43 +++++++++++++++++++++---------------------- src/main.rs | 28 +++++++++------------------- 2 files changed, 30 insertions(+), 41 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index e841e481..d1c1e4b3 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -2,14 +2,16 @@ use crate::{ image_editing::EditState, scrubber::Scrubber, settings::PersistentSettings, - utils::{ExtendedImageInfo, Frame, Player}, ImageExt, + utils::{ExtendedImageInfo, Frame, Player} }; +use notan::draw::*; +use crate::Draw; use egui_notify::Toasts; use image::RgbaImage; use image::imageops; use nalgebra::Vector2; use notan::{egui::epaint::ahash::HashMap, prelude::Texture, AppState}; -use notan::prelude::{Graphics, TextureFilter}; +use notan::prelude::{Graphics, TextureFilter, BlendMode}; use std::{ path::PathBuf, sync::mpsc::{self, Receiver, Sender}, @@ -165,6 +167,23 @@ impl TexWrap{ } } + pub fn draw_textures(&self,draw: &mut Draw, translation_x:f32, translation_y:f32, scale: f32){ + let mut tex_idx = 0; + for row_idx in 0..self.row_count + { + let translate_y = translation_y+scale*row_idx as f32*self.row_translation as f32; + for col_idx in 0..self.col_count + { + let translate_x = translation_x+scale*col_idx as f32 *self.col_translation as f32; + draw.image(&self.texture_array[tex_idx]) + .blend_mode(BlendMode::NORMAL) + .scale(scale, scale) + .translate(translate_x, translate_y); + tex_idx += 1; + } + } + } + pub fn update_textures(&mut self, gfx: &mut Graphics, image: &RgbaImage){ if(self.col_count==1 && self.row_count==1){ if let Err(e) = gfx.update_texture(&mut self.texture_array[0]).with_data(image).update() { @@ -209,26 +228,6 @@ impl TexWrap{ } } -// Implement `Iterator` for `Fibonacci`. -// The `Iterator` trait only requires a method to be defined for the `next` element. -/*impl Iterator for TexWrap { - // We can refer to this type using Self::Item - type Item = (u32,u32, Texture); - - // Here, we define the sequence using `.curr` and `.next`. - // The return type is `Option`: - // * When the `Iterator` is finished, `None` is returned. - // * Otherwise, the next value is wrapped in `Some` and returned. - // We use Self::Item in the return type, so we can change - // the type without having to update the function signatures. - fn next(&mut self) -> Option { - - self.index +=1; - - None - } -}*/ - /// The state of the application #[derive(AppState)] pub struct OculanteState { diff --git a/src/main.rs b/src/main.rs index 223cc93d..3c6de18c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1078,20 +1078,10 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O } } if state.tiling < 2 { - let mut tex_idx = 0; - for row_idx in 0..texture.row_count - { - let translate_y = state.image_geometry.offset.y+state.image_geometry.scale*row_idx as f32*texture.row_translation as f32; - for col_idx in 0..texture.col_count - { - let translate_x = state.image_geometry.offset.x+state.image_geometry.scale*col_idx as f32 *texture.col_translation as f32; - draw.image(&texture.texture_array[tex_idx]) - .blend_mode(BlendMode::NORMAL) - .scale(state.image_geometry.scale, state.image_geometry.scale) - .translate(translate_x, translate_y); - tex_idx += 1; - } - } + texture.draw_textures(&mut draw, + state.image_geometry.offset.x, + state.image_geometry.offset.y, + state.image_geometry.scale); } else { //TODO: How to implement this efficient? draw.pattern(&texture.texture_array[0]) @@ -1126,11 +1116,11 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O * state.image_geometry.scale > app.window().size().0 as f32; - if show_minimap { //TODO! - draw.image(&texture.texture_array[0]) - .blend_mode(BlendMode::NORMAL) - .translate(offset_x, 100.) - .scale(scale, scale); + if show_minimap { + texture.draw_textures(&mut draw, + offset_x, + 100., + scale); } } From 90b63c05b41577ed8e61e1620341951472143328 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 29 Apr 2024 19:17:54 +0200 Subject: [PATCH 06/29] Try tow draw preview image --- src/appstate.rs | 56 +++++++++++++++++++++++++++++++++++++++--- src/main.rs | 2 +- src/ui.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 114 insertions(+), 9 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index d1c1e4b3..d70726c1 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -57,6 +57,18 @@ pub struct TexWrap{ pub size_vec:(f32,f32) // The whole Texture Array size } +pub struct TextureResponse<'a>{ + pub texture: &'a Texture, + pub u_start_global : f32, + pub v_start_global : f32, + pub u_offset_global : f32, + pub v_offset_global : f32, + pub u_tex_right_global : f32, + pub v_tex_bottom_global : f32, + pub u_scale:f32, + pub v_scale:f32 +} + impl TexWrap{ /*pub fn new(texture: Texture) -> Self{ let s = texture.size(); @@ -118,7 +130,7 @@ impl TexWrap{ let im_w = image.width(); let im_h = image.height(); let s = (im_w as f32, im_h as f32); - let max_texture_size = gfx.limits().max_texture_size; + let max_texture_size = 128;//gfx.limits().max_texture_size; let col_count = (im_w as f32/max_texture_size as f32).ceil() as u32; let row_count = (im_h as f32/max_texture_size as f32).ceil() as u32; @@ -141,7 +153,7 @@ impl TexWrap{ col_increment, im_w-tex_start_x ); - print!("{0},{1},{2},{3}",tex_start_y, tex_height, tex_start_x, tex_width); + let sub_img = imageops::crop_imm(image, tex_start_x, tex_start_y, tex_width, tex_height); let my_img = sub_img.to_image(); let tex = fuuun(gfx, my_img.as_ref(), my_img.width(), my_img.height(), linear_mag_filter); @@ -203,7 +215,7 @@ impl TexWrap{ self.col_translation, image.width()-tex_start_x ); - print!("{0},{1},{2},{3}",tex_start_y, tex_height, tex_start_x, tex_width); + let sub_img = imageops::crop_imm(image, tex_start_x, tex_start_y, tex_width, tex_height); let my_img = sub_img.to_image(); if let Err(e) = gfx.update_texture(&mut self.texture_array[tex_index]).with_data(my_img.as_ref()).update() { @@ -215,6 +227,44 @@ impl TexWrap{ } } + pub fn get_texture_at_uv(&self, ua:f32, va:f32)->TextureResponse { + let v = (va).max(0.0).min(1.0); + let u = ua.max(0.0).min(1.0); + let x = u*self.width(); + let y = v*self.height(); + + let x_idx = (x /self.col_translation as f32).floor() as u32; + let y_idx = (y /self.row_translation as f32).floor() as u32; + let tex_idx = (y_idx*self.col_count+x_idx).min((self.texture_array.len() as i32 -1) as u32); + + let tex_top = y_idx*self.row_translation; + let tex_left = x_idx*self.col_translation; + let tex_bottom = tex_top+self.row_translation; + let tex_right = tex_left+self.col_translation; + + let u_start_global = tex_left as f32/self.width(); + let v_start_global = tex_top as f32/self.height(); + + let u_offset = (x-tex_left as f32)/self.width(); + let v_offset = (y-tex_top as f32)/self.height(); + + let u_tex_right = (tex_right) as f32 /self.width(); + let v_tex_bottom = (tex_bottom) as f32 /self.height(); + let u_scale = self.col_translation as f32/self.width(); + let v_scale = self.row_translation as f32/self.height(); + //TexWrap { tex: texture, size_vec:s } + TextureResponse {texture: &self.texture_array[tex_idx as usize], + u_start_global:u_start_global, + v_start_global:v_start_global, + u_offset_global:u_offset, + v_offset_global:v_offset, + u_tex_right_global:u_tex_right, + v_tex_bottom_global:v_tex_bottom, + u_scale:u_scale, + v_scale:v_scale } + //(&self.texture_array[tex_idx as usize],u_offset, v_offset, u_tex_right, v_tex_bottom) + } + pub fn size(&self)->(f32,f32){ return self.size_vec; } diff --git a/src/main.rs b/src/main.rs index 3c6de18c..20676e5b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -897,7 +897,7 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O if let Some(tex) = &mut state.current_texture { if tex.width() as u32 == img.width() && tex.height() as u32 == img.height() { - img.update_texture_with_texwrap(gfx, tex); //TODO: Kachel-Update + img.update_texture_with_texwrap(gfx, tex); } else { state.current_texture = img.to_texture(gfx, state.persistent_settings.linear_mag_filter); } diff --git a/src/ui.rs b/src/ui.rs index e2d40334..2bcd1fcd 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -334,7 +334,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { let uv_size = (scale, scale * ratio); - let preview_rect = ui + /*let preview_rect = ui .add( egui::Image::new(tex_id) .maintain_aspect_ratio(false) @@ -344,13 +344,68 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { uv_center.1 - uv_size.1..=uv_center.1 + uv_size.1, )), ) - .rect; + .rect;*/ + + + let end_cursor_x = uv_center.0 + uv_size.0; + let end_cursor_y = uv_center.1 + uv_size.1; + print!("Schdard end_cursor_x{} ",end_cursor_x); + println!("{} ",end_cursor_y); + println!(" {} ",end_cursor_y); + let mut curr_cursor_y = uv_center.1 - uv_size.1; + while(curr_cursor_y Date: Mon, 29 Apr 2024 19:18:32 +0200 Subject: [PATCH 07/29] Ultra sized images --- tests/ultrahigh.png | Bin 0 -> 101628 bytes tests/ultrasize.png | Bin 0 -> 341910 bytes tests/ultrawide.png | Bin 0 -> 343618 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/ultrahigh.png create mode 100644 tests/ultrasize.png create mode 100644 tests/ultrawide.png diff --git a/tests/ultrahigh.png b/tests/ultrahigh.png new file mode 100644 index 0000000000000000000000000000000000000000..9cb5ff6603f1c3f5769ebcb24440355e3088b425 GIT binary patch literal 101628 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 Ie(=Ws0-J!k8UO$Q literal 0 HcmV?d00001 diff --git a/tests/ultrasize.png b/tests/ultrasize.png new file mode 100644 index 0000000000000000000000000000000000000000..1615803f673b5b37fd3f5a08ebe518978f5ac6aa GIT binary patch literal 341910 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 HMQ{FpAZ;TB literal 0 HcmV?d00001 diff --git a/tests/ultrawide.png b/tests/ultrawide.png new file mode 100644 index 0000000000000000000000000000000000000000..b531085eb4beff6d2e174efdf30f521010af9e8a GIT binary patch literal 343618 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 literal 0 HcmV?d00001 From 020c314ce2472027b1889213667873d6575f86eb Mon Sep 17 00:00:00 2001 From: Simon Wezstein Date: Mon, 29 Apr 2024 22:18:02 +0200 Subject: [PATCH 08/29] Preview image now (mostly) renders ok. --- src/appstate.rs | 53 +++++++++++++++++++++++---------------- src/ui.rs | 66 +++++++++++++++++++++++++++---------------------- 2 files changed, 68 insertions(+), 51 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index d70726c1..2c32eba2 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -59,12 +59,14 @@ pub struct TexWrap{ pub struct TextureResponse<'a>{ pub texture: &'a Texture, - pub u_start_global : f32, - pub v_start_global : f32, - pub u_offset_global : f32, - pub v_offset_global : f32, + pub u_tex_left_global : f32, + pub v_tex_top_global : f32, + pub u_offset_texture : f32, + pub v_offset_texture : f32, pub u_tex_right_global : f32, pub v_tex_bottom_global : f32, + pub u_tex_next_right_global : f32, + pub v_tex_next_bottom_global : f32, pub u_scale:f32, pub v_scale:f32 } @@ -233,33 +235,42 @@ impl TexWrap{ let x = u*self.width(); let y = v*self.height(); - let x_idx = (x /self.col_translation as f32).floor() as u32; - let y_idx = (y /self.row_translation as f32).floor() as u32; - let tex_idx = (y_idx*self.col_count+x_idx).min((self.texture_array.len() as i32 -1) as u32); + let x_idx = (x /self.col_translation as f32).floor() as i32; + let y_idx = (y /self.row_translation as f32).floor() as i32; + let tex_idx = (y_idx*self.col_count as i32+x_idx).min((self.texture_array.len() as i32 -1)); - let tex_top = y_idx*self.row_translation; - let tex_left = x_idx*self.col_translation; - let tex_bottom = tex_top+self.row_translation; - let tex_right = tex_left+self.col_translation; + + let tex_left = x_idx*self.col_translation as i32; + let tex_top = y_idx*self.row_translation as i32; + + let tex_right = tex_left+self.col_translation as i32; + let tex_bottom = tex_top+self.row_translation as i32; + let tex_right_next = tex_left+self.col_translation as i32; + let tex_bottom_next = tex_top+self.row_translation as i32; - let u_start_global = tex_left as f32/self.width(); - let v_start_global = tex_top as f32/self.height(); + let u_tex_left_global = tex_left as f32/self.width(); + let v_tex_top_global = tex_top as f32/self.height(); - let u_offset = (x-tex_left as f32)/self.width(); - let v_offset = (y-tex_top as f32)/self.height(); + let u_offset = (x-tex_left as f32)/self.col_translation as f32; + let v_offset = (y-tex_top as f32)/self.row_translation as f32; - let u_tex_right = (tex_right) as f32 /self.width(); - let v_tex_bottom = (tex_bottom) as f32 /self.height(); + let u_tex_right = tex_right as f32 /self.width(); + let v_tex_bottom = tex_bottom as f32 /self.height(); + let u_tex_next_right_global = tex_right_next as f32 /self.width(); + let v_tex_next_bottom_global = tex_bottom_next as f32 /self.height(); + let u_scale = self.col_translation as f32/self.width(); let v_scale = self.row_translation as f32/self.height(); //TexWrap { tex: texture, size_vec:s } TextureResponse {texture: &self.texture_array[tex_idx as usize], - u_start_global:u_start_global, - v_start_global:v_start_global, - u_offset_global:u_offset, - v_offset_global:v_offset, + u_tex_left_global, + v_tex_top_global, + u_offset_texture:u_offset, + v_offset_texture:v_offset, u_tex_right_global:u_tex_right, v_tex_bottom_global:v_tex_bottom, + u_tex_next_right_global, + v_tex_next_bottom_global, u_scale:u_scale, v_scale:v_scale } //(&self.texture_array[tex_idx as usize],u_offset, v_offset, u_tex_right, v_tex_bottom) diff --git a/src/ui.rs b/src/ui.rs index 2bcd1fcd..a976e48a 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -347,40 +347,43 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { .rect;*/ - let end_cursor_x = uv_center.0 + uv_size.0; - let end_cursor_y = uv_center.1 + uv_size.1; - print!("Schdard end_cursor_x{} ",end_cursor_x); - println!("{} ",end_cursor_y); - println!(" {} ",end_cursor_y); - let mut curr_cursor_y = uv_center.1 - uv_size.1; - while(curr_cursor_y Date: Sun, 5 May 2024 14:29:23 +0200 Subject: [PATCH 09/29] Adding calculation of preview bounding box --- src/appstate.rs | 3 +-- src/ui.rs | 24 +++++++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index 2c32eba2..77695055 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -261,7 +261,7 @@ impl TexWrap{ let u_scale = self.col_translation as f32/self.width(); let v_scale = self.row_translation as f32/self.height(); - //TexWrap { tex: texture, size_vec:s } + TextureResponse {texture: &self.texture_array[tex_idx as usize], u_tex_left_global, v_tex_top_global, @@ -273,7 +273,6 @@ impl TexWrap{ v_tex_next_bottom_global, u_scale:u_scale, v_scale:v_scale } - //(&self.texture_array[tex_idx as usize],u_offset, v_offset, u_tex_right, v_tex_bottom) } pub fn size(&self)->(f32,f32){ diff --git a/src/ui.rs b/src/ui.rs index a976e48a..061aaeee 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -346,7 +346,9 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { ) .rect;*/ - + let mut bbox_tl = egui::pos2(f32::MAX, f32::MAX); + let mut bbox_br = egui::pos2(f32::MIN, f32::MIN); + let end_cursor_u = uv_center.0 + uv_size.0; let end_cursor_v = uv_center.1 + uv_size.1; @@ -367,6 +369,8 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { while(curr_cursor_u Date: Sun, 5 May 2024 14:47:57 +0200 Subject: [PATCH 10/29] Adding truncation for u/v > 1.0 --- src/appstate.rs | 10 ++++------ src/ui.rs | 16 +++++++++++----- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index 77695055..f0bb2b85 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -63,8 +63,8 @@ pub struct TextureResponse<'a>{ pub v_tex_top_global : f32, pub u_offset_texture : f32, pub v_offset_texture : f32, - pub u_tex_right_global : f32, - pub v_tex_bottom_global : f32, + u_tex_right_global : f32, + v_tex_bottom_global : f32, pub u_tex_next_right_global : f32, pub v_tex_next_bottom_global : f32, pub u_scale:f32, @@ -132,11 +132,9 @@ impl TexWrap{ let im_w = image.width(); let im_h = image.height(); let s = (im_w as f32, im_h as f32); - let max_texture_size = 128;//gfx.limits().max_texture_size; + let max_texture_size = 128;//gfx.limits().max_texture_size; // let col_count = (im_w as f32/max_texture_size as f32).ceil() as u32; - let row_count = (im_h as f32/max_texture_size as f32).ceil() as u32; - - + let row_count = (im_h as f32/max_texture_size as f32).ceil() as u32; let mut a:Vec = Vec::new(); let row_increment = std::cmp::min(max_texture_size, im_h); diff --git a/src/ui.rs b/src/ui.rs index 061aaeee..4df787e0 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -374,10 +374,16 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { let curr_tex = texture.get_texture_at_uv(curr_cursor_u, curr_cursor_v); //Where does the picked texture end globally? - let curr_tex_u_end = f32::min(curr_tex.u_tex_right_global, end_cursor_u); - curr_tex_v_end = f32::min(curr_tex.v_tex_bottom_global, end_cursor_v); + let mut curr_tex_u_end = f32::min(curr_tex.u_tex_next_right_global, end_cursor_u); + curr_tex_v_end = f32::min(curr_tex.v_tex_next_bottom_global, end_cursor_v); - + if end_cursor_u>1.0 && f32::abs(curr_tex.u_tex_next_right_global-1.0)< f32::EPSILON { + curr_tex_u_end = end_cursor_u; + } + + if end_cursor_v>1.0 && f32::abs(curr_tex.v_tex_next_bottom_global-1.0)< f32::EPSILON { + curr_tex_v_end = end_cursor_v; + } //The uv coordinates to draw the picked texture let u_offset_texture_snipped = curr_tex.u_offset_texture; @@ -411,8 +417,8 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { bbox_br.x = bbox_br.x.max(r_ret.right()); bbox_br.y = bbox_br.y.max(r_ret.bottom()); - curr_cursor_u = curr_tex.u_tex_next_right_global; - curr_tex_v_end = curr_tex.v_tex_next_bottom_global; + curr_cursor_u = curr_tex_u_end; + curr_tex_v_end = curr_tex_v_end; } }); From ded90f58421debe284d5d1bb5475a60b5b667088 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 9 May 2024 17:04:45 +0200 Subject: [PATCH 11/29] Better preview image rendering --- src/appstate.rs | 4 +- src/ui.rs | 124 +++++++++++++++++++++++++++++++----------------- 2 files changed, 83 insertions(+), 45 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index f0bb2b85..658bfd06 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -63,8 +63,8 @@ pub struct TextureResponse<'a>{ pub v_tex_top_global : f32, pub u_offset_texture : f32, pub v_offset_texture : f32, - u_tex_right_global : f32, - v_tex_bottom_global : f32, + pub u_tex_right_global : f32, + pub v_tex_bottom_global : f32, pub u_tex_next_right_global : f32, pub v_tex_next_bottom_global : f32, pub u_scale:f32, diff --git a/src/ui.rs b/src/ui.rs index 4df787e0..ff15890f 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -26,8 +26,9 @@ use log::{debug, error, info}; use mouse_position::mouse_position::Mouse; use notan::{ egui::{self, *}, - prelude::{App, Graphics}, + prelude::{App, Graphics, BlendMode}, }; +use notan::draw::*; use std::{collections::BTreeSet, ops::RangeInclusive, path::PathBuf, time::Instant}; use strum::IntoEnumIterator; const PANEL_WIDTH: f32 = 240.0; @@ -329,10 +330,13 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { ui.end_row(); }); + + //let mut draw = gfx.create_draw(); + // make sure aspect ratio is compensated for the square preview let ratio = texture.size().0 / texture.size().1; let uv_size = (scale, scale * ratio); - + let bg_color = Color32::BLACK.linear_multiply(0.5); /*let preview_rect = ui .add( @@ -354,35 +358,43 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { let curr_spacing = ui.spacing().item_spacing; - ui.spacing_mut().item_spacing = egui::vec2(0.0, 0.0); + let base_ui_curs = ui.cursor().min; //our start position + let mut curr_ui_curs = ui.cursor().min; //our start position + + let mut curr_cursor_v = uv_center.1 - uv_size.1; - ui.vertical(|ui| { + let mut counter_v = 0; //Safety measure... - while(curr_cursor_v1.0 && f32::abs(curr_tex.u_tex_next_right_global-1.0)< f32::EPSILON { + if end_cursor_u>1.0 && f32::abs(curr_tex.u_tex_right_global-1.0)< f32::EPSILON { curr_tex_u_end = end_cursor_u; + next_tex_u_begin = end_cursor_u; } - if end_cursor_v>1.0 && f32::abs(curr_tex.v_tex_next_bottom_global-1.0)< f32::EPSILON { + if end_cursor_v>1.0 && f32::abs(curr_tex.v_tex_bottom_global-1.0)< f32::EPSILON { curr_tex_v_end = end_cursor_v; + next_tex_v_begin = end_cursor_v; } //The uv coordinates to draw the picked texture @@ -394,43 +406,69 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { //Display size let u_size = desired_width*(curr_tex_u_end-curr_cursor_u)/(2.0*uv_size.0); let v_size = desired_width*(curr_tex_v_end-curr_cursor_v)/(2.0*uv_size.1); - - let tex_id2 = gfx.egui_register_texture(curr_tex.texture); - - let r_ret = ui - .add( - egui::Image::new(tex_id2) - .maintain_aspect_ratio(false) - .fit_to_exact_size(egui::Vec2::new(u_size, v_size) - ) - .uv(egui::Rect::from_x_y_ranges( - u_offset_texture_snipped ..=curr_tex_u_end_texture, - v_offset_texture_snipped ..=curr_tex_v_end_texture, - )) - .texture_options(TextureOptions::LINEAR) - ).rect; - - //Update coordinates for preview rectangle - bbox_tl.x = bbox_tl.x.min(r_ret.left()); - bbox_tl.y = bbox_tl.y.min(r_ret.top()); + last_v_size = v_size; + let curr_ui_curs_after = curr_ui_curs+Vec2::new(u_size, 0.0); - bbox_br.x = bbox_br.x.max(r_ret.right()); - bbox_br.y = bbox_br.y.max(r_ret.bottom()); + if(u_size<=f32::EPSILON) + { + print!("{}, ", u_size); + println!("{}", v_size); + curr_cursor_u += f32::EPSILON; + continue; + } - curr_cursor_u = curr_tex_u_end; - curr_tex_v_end = curr_tex_v_end; - } - }); - - curr_cursor_v = curr_tex_v_end; - }}); + let tex_id2 = gfx.egui_register_texture(curr_tex.texture); + let r_ret =egui::Rect::from_min_max(curr_ui_curs, curr_ui_curs_after+Vec2::new(0.0, v_size)); + //let r_ret = ui + //.add( + egui::Image::new(tex_id2) + .maintain_aspect_ratio(false) + .texture_options(TextureOptions::NEAREST) + .fit_to_exact_size(egui::Vec2::new(u_size, v_size)) + .uv(egui::Rect::from_x_y_ranges( + u_offset_texture_snipped ..=curr_tex_u_end_texture, + v_offset_texture_snipped ..=curr_tex_v_end_texture, + ) + ) + .paint_at(ui, r_ret); + //.texture_options(TextureOptions::LINEAR) + //).rect; + + /*draw.image(&curr_tex.texture) + .blend_mode(BlendMode::NORMAL) + //.scale(u_size, scale) + .size(u_size, v_size) + .translate(curr_ui_curs.x, curr_ui_curs.y);*/ + + /*ui.painter_at(r_ret).line_segment( + [Pos2::new(r_ret.left(), r_ret.bottom()) , Pos2::new(r_ret.right(), r_ret.bottom())], + Stroke::new(4., bg_color), + );*/ + + //Update coordinates for preview rectangle + bbox_tl.x = bbox_tl.x.min(r_ret.left()); + bbox_tl.y = bbox_tl.y.min(r_ret.top()); + + bbox_br.x = bbox_br.x.max(r_ret.right()); + bbox_br.y = bbox_br.y.max(r_ret.bottom()); + + curr_ui_curs = curr_ui_curs_after; + curr_cursor_u = next_tex_u_begin; + } + + curr_ui_curs+=Vec2::new(0.0, last_v_size); + curr_cursor_v = next_tex_v_begin; + } + //gfx.render(&draw); + let preview_rect = egui::Rect::from_min_max(bbox_tl, bbox_br); + ui.advance_cursor_after_rect(preview_rect); ui.spacing_mut().item_spacing = curr_spacing; let stroke_color = Color32::from_white_alpha(240); - let bg_color = Color32::BLACK.linear_multiply(0.5); + ui.painter_at(preview_rect).line_segment( [preview_rect.center_bottom(), preview_rect.center_top()], Stroke::new(4., bg_color), From 205665a1bcb9f41337253493646774c7e8feb142 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 9 May 2024 22:00:39 +0200 Subject: [PATCH 12/29] Now the preview is rendered fine besides the lines between the tiles. Algorithm has numerical stability issues. TODO: increase stability. --- src/appstate.rs | 26 ++++++++++++++++---------- src/ui.rs | 29 ++++++++++++++++++----------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index 658bfd06..7feb8e59 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -228,6 +228,9 @@ impl TexWrap{ } pub fn get_texture_at_uv(&self, ua:f32, va:f32)->TextureResponse { + let xa = ua*self.width(); + let ya = va*self.height(); + let v = (va).max(0.0).min(1.0); let u = ua.max(0.0).min(1.0); let x = u*self.width(); @@ -236,31 +239,34 @@ impl TexWrap{ let x_idx = (x /self.col_translation as f32).floor() as i32; let y_idx = (y /self.row_translation as f32).floor() as i32; let tex_idx = (y_idx*self.col_count as i32+x_idx).min((self.texture_array.len() as i32 -1)); - + let my_tex = &self.texture_array[tex_idx as usize]; let tex_left = x_idx*self.col_translation as i32; let tex_top = y_idx*self.row_translation as i32; - let tex_right = tex_left+self.col_translation as i32; - let tex_bottom = tex_top+self.row_translation as i32; - let tex_right_next = tex_left+self.col_translation as i32; - let tex_bottom_next = tex_top+self.row_translation as i32; + //the current texture might be smaller than the set translation. (Last element on x or y axis) + let tex_right_next = tex_left+my_tex.width() as i32; + let tex_bottom_next = tex_top+my_tex.height() as i32; + let tex_right = tex_right_next; + let tex_bottom = tex_bottom_next; + let u_scale = my_tex.width() as f32/self.width(); + let v_scale = my_tex.height() as f32/self.height(); + let u_tex_left_global = tex_left as f32/self.width(); let v_tex_top_global = tex_top as f32/self.height(); - let u_offset = (x-tex_left as f32)/self.col_translation as f32; - let v_offset = (y-tex_top as f32)/self.row_translation as f32; + let u_offset = (xa-tex_left as f32)/my_tex.width(); + let v_offset = (ya-tex_top as f32)/my_tex.height(); let u_tex_right = tex_right as f32 /self.width(); let v_tex_bottom = tex_bottom as f32 /self.height(); let u_tex_next_right_global = tex_right_next as f32 /self.width(); let v_tex_next_bottom_global = tex_bottom_next as f32 /self.height(); - let u_scale = self.col_translation as f32/self.width(); - let v_scale = self.row_translation as f32/self.height(); - TextureResponse {texture: &self.texture_array[tex_idx as usize], + + TextureResponse {texture: my_tex, u_tex_left_global, v_tex_top_global, u_offset_texture:u_offset, diff --git a/src/ui.rs b/src/ui.rs index ff15890f..fe2ceb61 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -409,12 +409,17 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { last_v_size = v_size; let curr_ui_curs_after = curr_ui_curs+Vec2::new(u_size, 0.0); + //Safety measure: the cursor could perfectly hit the boundary if(u_size<=f32::EPSILON) - { - print!("{}, ", u_size); - println!("{}", v_size); - curr_cursor_u += f32::EPSILON; - continue; + { + curr_cursor_u += f32::EPSILON; + continue; + } + + if(v_size<=f32::EPSILON) + { + curr_cursor_v += f32::EPSILON; + continue; } @@ -424,7 +429,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { //.add( egui::Image::new(tex_id2) .maintain_aspect_ratio(false) - .texture_options(TextureOptions::NEAREST) + .fit_to_exact_size(egui::Vec2::new(u_size, v_size)) .uv(egui::Rect::from_x_y_ranges( u_offset_texture_snipped ..=curr_tex_u_end_texture, @@ -447,11 +452,12 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { );*/ //Update coordinates for preview rectangle - bbox_tl.x = bbox_tl.x.min(r_ret.left()); - bbox_tl.y = bbox_tl.y.min(r_ret.top()); + //We round because of numerical instability. TODO: Improve! + bbox_tl.x = bbox_tl.x.min(r_ret.left()).round(); + bbox_tl.y = bbox_tl.y.min(r_ret.top()).round(); - bbox_br.x = bbox_br.x.max(r_ret.right()); - bbox_br.y = bbox_br.y.max(r_ret.bottom()); + bbox_br.x = bbox_br.x.max(r_ret.right()).round(); + bbox_br.y = bbox_br.y.max(r_ret.bottom()).round(); curr_ui_curs = curr_ui_curs_after; curr_cursor_u = next_tex_u_begin; @@ -461,9 +467,10 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { curr_cursor_v = next_tex_v_begin; } - //gfx.render(&draw); let preview_rect = egui::Rect::from_min_max(bbox_tl, bbox_br); + + println!("{}", preview_rect.bottom()); ui.advance_cursor_after_rect(preview_rect); ui.spacing_mut().item_spacing = curr_spacing; From e8ca1bb68a156818cc5c8cfaed4222cc4ec74902 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 10 May 2024 08:58:05 +0200 Subject: [PATCH 13/29] Switching preview tiling to f64 calculations to improve numerical stability. --- src/appstate.rs | 60 ++++++++++++++--------------- src/image_loader.rs | 4 +- src/ui.rs | 92 ++++++++++++++++++++++++--------------------- 3 files changed, 81 insertions(+), 75 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index 7feb8e59..8d428945 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -59,16 +59,16 @@ pub struct TexWrap{ pub struct TextureResponse<'a>{ pub texture: &'a Texture, - pub u_tex_left_global : f32, - pub v_tex_top_global : f32, - pub u_offset_texture : f32, - pub v_offset_texture : f32, - pub u_tex_right_global : f32, - pub v_tex_bottom_global : f32, - pub u_tex_next_right_global : f32, - pub v_tex_next_bottom_global : f32, - pub u_scale:f32, - pub v_scale:f32 + pub u_tex_left_global : f64, + pub v_tex_top_global : f64, + pub u_offset_texture : f64, + pub v_offset_texture : f64, + pub u_tex_right_global : f64, + pub v_tex_bottom_global : f64, + pub u_tex_next_right_global : f64, + pub v_tex_next_bottom_global : f64, + pub u_scale:f64, + pub v_scale:f64 } impl TexWrap{ @@ -132,7 +132,7 @@ impl TexWrap{ let im_w = image.width(); let im_h = image.height(); let s = (im_w as f32, im_h as f32); - let max_texture_size = 128;//gfx.limits().max_texture_size; // + let max_texture_size = gfx.limits().max_texture_size; //128;// let col_count = (im_w as f32/max_texture_size as f32).ceil() as u32; let row_count = (im_h as f32/max_texture_size as f32).ceil() as u32; @@ -227,17 +227,17 @@ impl TexWrap{ } } - pub fn get_texture_at_uv(&self, ua:f32, va:f32)->TextureResponse { - let xa = ua*self.width(); - let ya = va*self.height(); + pub fn get_texture_at_uv(&self, ua:f64, va:f64)->TextureResponse { + let xa = ua as f64*self.width()as f64; + let ya = va as f64*self.height()as f64; - let v = (va).max(0.0).min(1.0); - let u = ua.max(0.0).min(1.0); - let x = u*self.width(); - let y = v*self.height(); + let v = (va).max(0.0).min(1.0)as f64; + let u = ua.max(0.0).min(1.0)as f64; + let x = u*self.width()as f64; + let y = v*self.height()as f64; - let x_idx = (x /self.col_translation as f32).floor() as i32; - let y_idx = (y /self.row_translation as f32).floor() as i32; + let x_idx = (x /self.col_translation as f64).floor() as i32; + let y_idx = (y /self.row_translation as f64).floor() as i32; let tex_idx = (y_idx*self.col_count as i32+x_idx).min((self.texture_array.len() as i32 -1)); let my_tex = &self.texture_array[tex_idx as usize]; @@ -249,20 +249,20 @@ impl TexWrap{ let tex_bottom_next = tex_top+my_tex.height() as i32; let tex_right = tex_right_next; let tex_bottom = tex_bottom_next; - let u_scale = my_tex.width() as f32/self.width(); - let v_scale = my_tex.height() as f32/self.height(); + let u_scale = my_tex.width() as f64/self.width() as f64; + let v_scale = my_tex.height() as f64/self.height() as f64; - let u_tex_left_global = tex_left as f32/self.width(); - let v_tex_top_global = tex_top as f32/self.height(); + let u_tex_left_global = tex_left as f64/self.width() as f64; + let v_tex_top_global = tex_top as f64/self.height() as f64; - let u_offset = (xa-tex_left as f32)/my_tex.width(); - let v_offset = (ya-tex_top as f32)/my_tex.height(); + let u_offset = (xa-tex_left as f64)/my_tex.width()as f64; + let v_offset = (ya-tex_top as f64)/my_tex.height()as f64; - let u_tex_right = tex_right as f32 /self.width(); - let v_tex_bottom = tex_bottom as f32 /self.height(); - let u_tex_next_right_global = tex_right_next as f32 /self.width(); - let v_tex_next_bottom_global = tex_bottom_next as f32 /self.height(); + let u_tex_right = tex_right as f64 /self.width()as f64; + let v_tex_bottom = tex_bottom as f64 /self.height()as f64; + let u_tex_next_right_global = tex_right_next as f64 /self.width()as f64; + let v_tex_next_bottom_global = tex_bottom_next as f64 /self.height()as f64; diff --git a/src/image_loader.rs b/src/image_loader.rs index 6ea96010..4ac7de15 100644 --- a/src/image_loader.rs +++ b/src/image_loader.rs @@ -484,8 +484,8 @@ pub fn open_image(img_location: &Path) -> Result> { let mut decoder = PngDecoder::new(&contents); decoder.set_options( DecoderOptions::new_fast() - .set_max_height(50000) - .set_max_width(50000), + .set_max_height(128000) + .set_max_width(128000), ); //animation diff --git a/src/ui.rs b/src/ui.rs index fe2ceb61..037457c3 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -249,17 +249,17 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { .show(ui, |ui| { if let Some(texture) = &state.current_texture { // texture. - let tex_id = gfx.egui_register_texture(&texture.texture_array[0]); + //let tex_id = gfx.egui_register_texture(&texture.texture_array[0]); // width of image widget // let desired_width = ui.available_width() - ui.spacing().indent; - let desired_width = PANEL_WIDTH - PANEL_WIDGET_OFFSET; + let desired_width = PANEL_WIDTH as f64 - PANEL_WIDGET_OFFSET as f64; - let scale = (desired_width / 8.) / texture.size().0; + let scale = (desired_width / 8.) / texture.size().0 as f64; let uv_center = ( - state.cursor_relative.x / state.image_geometry.dimensions.0 as f32, - (state.cursor_relative.y / state.image_geometry.dimensions.1 as f32), + state.cursor_relative.x as f64 / state.image_geometry.dimensions.0 as f64, + (state.cursor_relative.y as f64 / state.image_geometry.dimensions.1 as f64), ); egui::Grid::new("info").show(ui, |ui| { @@ -335,7 +335,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { // make sure aspect ratio is compensated for the square preview let ratio = texture.size().0 / texture.size().1; - let uv_size = (scale, scale * ratio); + let uv_size = (scale, scale * ratio as f64); let bg_color = Color32::BLACK.linear_multiply(0.5); /*let preview_rect = ui @@ -356,11 +356,12 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { let end_cursor_u = uv_center.0 + uv_size.0; let end_cursor_v = uv_center.1 + uv_size.1; - let curr_spacing = ui.spacing().item_spacing; - - let base_ui_curs = ui.cursor().min; //our start position - let mut curr_ui_curs = ui.cursor().min; //our start position + + //let base_ui_curs = ui.cursor().min; //our start position + + let base_ui_curs = nalgebra::Vector2::new(ui.cursor().min.x as f64, ui.cursor().min.y as f64); + let mut curr_ui_curs = base_ui_curs; //our start position let mut curr_cursor_v = uv_center.1 - uv_size.1; @@ -369,9 +370,9 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { counter_v += 1; let mut counter_u = 0; //Safety measure... let mut curr_cursor_u = uv_center.0 - uv_size.0; - let mut curr_tex_v_end:f32 = 0.0; - let mut next_tex_v_begin:f32 = 0.0; - let mut last_v_size: f32 = 0.0; + let mut curr_tex_v_end:f64 = 0.0; + let mut next_tex_v_begin:f64 = 0.0; + let mut last_v_size: f64 = 0.0; curr_ui_curs.x = base_ui_curs.x; @@ -382,17 +383,17 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { let curr_tex = texture.get_texture_at_uv(curr_cursor_u, curr_cursor_v); //Where does the picked texture end globally? - let mut curr_tex_u_end = f32::min(curr_tex.u_tex_right_global, end_cursor_u); - curr_tex_v_end = f32::min(curr_tex.v_tex_bottom_global, end_cursor_v); - let mut next_tex_u_begin = f32::min(curr_tex.u_tex_next_right_global, end_cursor_u); - next_tex_v_begin = f32::min(curr_tex.v_tex_next_bottom_global, end_cursor_v); + let mut curr_tex_u_end = f64::min(curr_tex.u_tex_right_global, end_cursor_u); + curr_tex_v_end = f64::min(curr_tex.v_tex_bottom_global, end_cursor_v); + let mut next_tex_u_begin = f64::min(curr_tex.u_tex_next_right_global, end_cursor_u); + next_tex_v_begin = f64::min(curr_tex.v_tex_next_bottom_global, end_cursor_v); - if end_cursor_u>1.0 && f32::abs(curr_tex.u_tex_right_global-1.0)< f32::EPSILON { + if end_cursor_u>1.0 && f64::abs(curr_tex.u_tex_right_global-1.0)< f64::EPSILON { curr_tex_u_end = end_cursor_u; next_tex_u_begin = end_cursor_u; } - if end_cursor_v>1.0 && f32::abs(curr_tex.v_tex_bottom_global-1.0)< f32::EPSILON { + if end_cursor_v>1.0 && f64::abs(curr_tex.v_tex_bottom_global-1.0)< f64::EPSILON { curr_tex_v_end = end_cursor_v; next_tex_v_begin = end_cursor_v; } @@ -406,37 +407,43 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { //Display size let u_size = desired_width*(curr_tex_u_end-curr_cursor_u)/(2.0*uv_size.0); let v_size = desired_width*(curr_tex_v_end-curr_cursor_v)/(2.0*uv_size.1); + last_v_size = v_size; - let curr_ui_curs_after = curr_ui_curs+Vec2::new(u_size, 0.0); + let curr_ui_curs_after = curr_ui_curs+nalgebra::Vector2::new(u_size, 0.0); //Safety measure: the cursor could perfectly hit the boundary - if(u_size<=f32::EPSILON) + if(u_size<=f64::EPSILON) { - curr_cursor_u += f32::EPSILON; + curr_cursor_u += f64::EPSILON; continue; } - if(v_size<=f32::EPSILON) + if(v_size<=f64::EPSILON) { - curr_cursor_v += f32::EPSILON; + curr_cursor_v += f64::EPSILON; continue; } let tex_id2 = gfx.egui_register_texture(curr_tex.texture); - let r_ret =egui::Rect::from_min_max(curr_ui_curs, curr_ui_curs_after+Vec2::new(0.0, v_size)); + let draw_tl_32 = Pos2::new(curr_ui_curs.x as f32, curr_ui_curs.y as f32); + let draw_br_64 = curr_ui_curs_after+nalgebra::Vector2::new(0.0, v_size); + let draw_br_32 = Pos2::new(draw_br_64.x as f32, draw_br_64.y as f32); + let r_ret =egui::Rect::from_min_max(draw_tl_32, draw_br_32); //let r_ret = ui //.add( - egui::Image::new(tex_id2) - .maintain_aspect_ratio(false) - - .fit_to_exact_size(egui::Vec2::new(u_size, v_size)) - .uv(egui::Rect::from_x_y_ranges( - u_offset_texture_snipped ..=curr_tex_u_end_texture, - v_offset_texture_snipped ..=curr_tex_v_end_texture, - ) - ) - .paint_at(ui, r_ret); + egui::Image::new(tex_id2) + .maintain_aspect_ratio(false) + + .fit_to_exact_size(egui::Vec2::new(u_size as f32, v_size as f32)) + .uv(egui::Rect::from_x_y_ranges( + u_offset_texture_snipped as f32 ..=curr_tex_u_end_texture as f32, + v_offset_texture_snipped as f32 ..=curr_tex_v_end_texture as f32, + ) + ) + .paint_at(ui, r_ret); + + //.texture_options(TextureOptions::LINEAR) //).rect; @@ -453,26 +460,25 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { //Update coordinates for preview rectangle //We round because of numerical instability. TODO: Improve! - bbox_tl.x = bbox_tl.x.min(r_ret.left()).round(); - bbox_tl.y = bbox_tl.y.min(r_ret.top()).round(); + bbox_tl.x = bbox_tl.x.min(r_ret.left()); + bbox_tl.y = bbox_tl.y.min(r_ret.top()); - bbox_br.x = bbox_br.x.max(r_ret.right()).round(); - bbox_br.y = bbox_br.y.max(r_ret.bottom()).round(); + bbox_br.x = bbox_br.x.max(r_ret.right()); + bbox_br.y = bbox_br.y.max(r_ret.bottom()); curr_ui_curs = curr_ui_curs_after; curr_cursor_u = next_tex_u_begin; } - curr_ui_curs+=Vec2::new(0.0, last_v_size); + curr_ui_curs += nalgebra::Vector2::new(0.0, last_v_size); curr_cursor_v = next_tex_v_begin; } let preview_rect = egui::Rect::from_min_max(bbox_tl, bbox_br); - - println!("{}", preview_rect.bottom()); + ui.advance_cursor_after_rect(preview_rect); - ui.spacing_mut().item_spacing = curr_spacing; + let stroke_color = Color32::from_white_alpha(240); From 097e4736f65465ba56b7d09f4bc255154458b694 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 10 May 2024 09:00:35 +0200 Subject: [PATCH 14/29] removing image rescaling for big textures --- src/utils.rs | 33 ++------------------------------- 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index 94896984..5422a99a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -288,9 +288,7 @@ pub fn send_image_threaded( Ok(frame_receiver) => { // _ = texture_sender // .clone() - // .send(Frame::new_reset(f.buffer.clone())); - - let cheat_max_texture_size:u32 = 65384; + // .send(Frame::new_reset(f.buffer.clone())); let mut first = true; for mut f in frame_receiver.iter() { @@ -305,34 +303,7 @@ pub fn send_image_threaded( if f.source == FrameSource::Still { debug!("Received image in {:?}", timer.elapsed()); - let largest_side = f.buffer.dimensions().0.max(f.buffer.dimensions().1); - - // Check if texture is too large to fit on the texture - if largest_side > cheat_max_texture_size { - _ = message_sender.send(Message::warn("This image exceeded the maximum resolution and will be be scaled down.")); - let scale_factor = cheat_max_texture_size as f32 / largest_side as f32; - let new_dimensions = ( - (f.buffer.dimensions().0 as f32 * scale_factor) - .min(cheat_max_texture_size as f32) - as u32, - (f.buffer.dimensions().1 as f32 * scale_factor) - .min(cheat_max_texture_size as f32) - as u32, - ); - - let mut frame = f; - - let op = ImageOperation::Resize { - dimensions: new_dimensions, - aspect: true, - filter: image_editing::ScaleFilter::Box, - }; - _ = op.process_image(&mut frame.buffer); - let _ = texture_sender.send(frame); - } else { - let _ = texture_sender.send(f); - } - + let _ = texture_sender.send(f); return; } if f.source == FrameSource::Animation { From a2b371e590ecc8cbef9b95b31a5c84fa2caf9bbb Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 10 May 2024 11:11:23 +0200 Subject: [PATCH 15/29] Implemented tile feature for the new Texture Array stuff. Texture Array from now on shouldn't be public. --- src/appstate.rs | 2 +- src/main.rs | 21 +++++++++++++-------- src/ui.rs | 46 +++++++++++++++------------------------------- 3 files changed, 29 insertions(+), 40 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index 8d428945..153e1b7d 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -49,7 +49,7 @@ impl Message { } pub struct TexWrap{ - pub texture_array:Vec, + texture_array:Vec, pub col_count:u32, pub row_count:u32, pub col_translation:u32, diff --git a/src/main.rs b/src/main.rs index 20676e5b..848f9684 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1083,14 +1083,19 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O state.image_geometry.offset.y, state.image_geometry.scale); } else { - //TODO: How to implement this efficient? - draw.pattern(&texture.texture_array[0]) - .scale(state.image_geometry.scale, state.image_geometry.scale) - .translate(state.image_geometry.offset.x, state.image_geometry.offset.y) - .size( - texture.texture_array[0].width() * state.tiling as f32, - texture.texture_array[0].height() * state.tiling as f32, - ); + + for yi in 0..state.tiling { + for xi in 0..state.tiling { + //The "old" version used only a static offset, is this correct? + let translate_x = xi as f32* texture.width()*state.image_geometry.scale + state.image_geometry.offset.x; + let translate_y = yi as f32* texture.height()*state.image_geometry.scale + state.image_geometry.offset.y; + + texture.draw_textures(&mut draw, + translate_x, + translate_y, + state.image_geometry.scale); + } + } } if state.persistent_settings.show_frame { diff --git a/src/ui.rs b/src/ui.rs index 037457c3..1539aad6 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -184,7 +184,7 @@ impl EguiExt for Ui { #[allow(unused)] pub fn image_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { if let Some(texture) = &state.current_texture { - let tex_id = gfx.egui_register_texture(&texture.texture_array[0]); //TODO: Adapt if needed + //let tex_id = gfx.egui_register_texture(&texture.texture_array[0]); //TODO: Adapt if needed let image_rect = Rect::from_center_size( Pos2::new( @@ -199,12 +199,12 @@ pub fn image_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { ) * state.image_geometry.scale, ); - egui::Painter::new(ctx.clone(), LayerId::background(), ctx.available_rect()).image( + /*egui::Painter::new(ctx.clone(), LayerId::background(), ctx.available_rect()).image( tex_id.id, image_rect, Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0)), Color32::WHITE, - ); + );*/ } // state.image_geometry.scale; @@ -248,11 +248,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { egui::ScrollArea::vertical().auto_shrink([false,true]) .show(ui, |ui| { if let Some(texture) = &state.current_texture { - // texture. - //let tex_id = gfx.egui_register_texture(&texture.texture_array[0]); - - // width of image widget - // let desired_width = ui.available_width() - ui.spacing().indent; + let desired_width = PANEL_WIDTH as f64 - PANEL_WIDGET_OFFSET as f64; let scale = (desired_width / 8.) / texture.size().0 as f64; @@ -331,8 +327,6 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { }); - //let mut draw = gfx.create_draw(); - // make sure aspect ratio is compensated for the square preview let ratio = texture.size().0 / texture.size().1; let uv_size = (scale, scale * ratio as f64); @@ -350,27 +344,24 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { ) .rect;*/ + //Pre initialize the rectangle coordinates of the preview window let mut bbox_tl = egui::pos2(f32::MAX, f32::MAX); let mut bbox_br = egui::pos2(f32::MIN, f32::MIN); + //The uv positions in the image, we iterate over + let mut curr_cursor_v = uv_center.1 - uv_size.1; let end_cursor_u = uv_center.0 + uv_size.0; let end_cursor_v = uv_center.1 + uv_size.1; - - - //let base_ui_curs = ui.cursor().min; //our start position - + //Ui position to start at let base_ui_curs = nalgebra::Vector2::new(ui.cursor().min.x as f64, ui.cursor().min.y as f64); let mut curr_ui_curs = base_ui_curs; //our start position - let mut curr_cursor_v = uv_center.1 - uv_size.1; - let mut counter_v = 0; //Safety measure... while(curr_cursor_v Date: Sun, 8 Sep 2024 21:00:47 +0200 Subject: [PATCH 16/29] Source code cleanup --- src/appstate.rs | 253 +--------------------------------------- src/main.rs | 4 +- src/texture_wrapper.rs | 256 +++++++++++++++++++++++++++++++++++++++++ src/ui.rs | 12 +- src/utils.rs | 13 +-- 5 files changed, 271 insertions(+), 267 deletions(-) create mode 100644 src/texture_wrapper.rs diff --git a/src/appstate.rs b/src/appstate.rs index 153e1b7d..e2675a89 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -2,21 +2,18 @@ use crate::{ image_editing::EditState, scrubber::Scrubber, settings::PersistentSettings, - utils::{ExtendedImageInfo, Frame, Player} + utils::{ExtendedImageInfo, Frame, Player}, + texture_wrapper::TexWrap }; -use notan::draw::*; -use crate::Draw; + use egui_notify::Toasts; use image::RgbaImage; -use image::imageops; use nalgebra::Vector2; use notan::{egui::epaint::ahash::HashMap, prelude::Texture, AppState}; -use notan::prelude::{Graphics, TextureFilter, BlendMode}; use std::{ path::PathBuf, sync::mpsc::{self, Receiver, Sender}, }; -use log::error; #[derive(Debug, Clone)] pub struct ImageGeometry { @@ -48,249 +45,7 @@ impl Message { } } -pub struct TexWrap{ - texture_array:Vec, - pub col_count:u32, - pub row_count:u32, - pub col_translation:u32, - pub row_translation:u32, - pub size_vec:(f32,f32) // The whole Texture Array size -} - -pub struct TextureResponse<'a>{ - pub texture: &'a Texture, - pub u_tex_left_global : f64, - pub v_tex_top_global : f64, - pub u_offset_texture : f64, - pub v_offset_texture : f64, - pub u_tex_right_global : f64, - pub v_tex_bottom_global : f64, - pub u_tex_next_right_global : f64, - pub v_tex_next_bottom_global : f64, - pub u_scale:f64, - pub v_scale:f64 -} - -impl TexWrap{ - /*pub fn new(texture: Texture) -> Self{ - let s = texture.size(); - TexWrap { tex: texture, size_vec:s } - }*/ - - //pub fn from_rgba_image_premult(gfx: &mut Graphics, linear_mag_filter: bool, image: &RgbaImage) -> Option{} - - pub fn from_rgbaimage(gfx: &mut Graphics, linear_mag_filter: bool, image: &RgbaImage) -> Option{ - Self::gen_from_rgbaimage(gfx, linear_mag_filter, image, Self::gen_texture_standard) - } - - pub fn from_rgbaimage_premult(gfx: &mut Graphics, linear_mag_filter: bool, image: &RgbaImage) -> Option{ - Self::gen_from_rgbaimage(gfx, linear_mag_filter, image, Self::gen_texture_premult) - } - fn gen_texture_standard(gfx: &mut Graphics, bytes:&[u8], width:u32, height:u32, linear_mag_filter:bool)-> Option - { - gfx.create_texture() - .from_bytes(bytes, width, height) - .with_mipmaps(true) - // .with_format(notan::prelude::TextureFormat::SRgba8) - // .with_premultiplied_alpha() - .with_filter( - TextureFilter::Linear, - if linear_mag_filter { - TextureFilter::Linear - } else { - TextureFilter::Nearest - }, - ) - // .with_wrap(TextureWrap::Clamp, TextureWrap::Clamp) - .build() - .ok() - } - - fn gen_texture_premult(gfx: &mut Graphics, bytes:&[u8], width:u32, height:u32, linear_mag_filter:bool)-> Option - { - gfx.create_texture() - .from_bytes(bytes, width, height) - .with_premultiplied_alpha() - .with_mipmaps(true) - // .with_format(notan::prelude::TextureFormat::SRgba8) - // .with_premultiplied_alpha() - .with_filter( - TextureFilter::Linear, - if linear_mag_filter { - TextureFilter::Linear - } else { - TextureFilter::Nearest - }, - ) - // .with_wrap(TextureWrap::Clamp, TextureWrap::Clamp) - .build() - .ok() - } - - fn gen_from_rgbaimage(gfx: &mut Graphics, linear_mag_filter: bool, image: &RgbaImage, fuuun: fn (&mut Graphics, &[u8], u32, u32, bool)-> Option) -> Option{ - let im_w = image.width(); - let im_h = image.height(); - let s = (im_w as f32, im_h as f32); - let max_texture_size = gfx.limits().max_texture_size; //128;// - let col_count = (im_w as f32/max_texture_size as f32).ceil() as u32; - let row_count = (im_h as f32/max_texture_size as f32).ceil() as u32; - - let mut a:Vec = Vec::new(); - let row_increment = std::cmp::min(max_texture_size, im_h); - let col_increment = std::cmp::min(max_texture_size, im_w); - let mut fine = true; - - for row_index in 0..row_count { - let tex_start_y = row_index*row_increment; - let tex_height = std::cmp::min( - row_increment, - im_h-tex_start_y - ); - for col_index in 0..col_count { - let tex_start_x = col_index*col_increment; - let tex_width = std::cmp::min( - col_increment, - im_w-tex_start_x - ); - - let sub_img = imageops::crop_imm(image, tex_start_x, tex_start_y, tex_width, tex_height); - let my_img = sub_img.to_image(); - let tex = fuuun(gfx, my_img.as_ref(), my_img.width(), my_img.height(), linear_mag_filter); - - if let Some(t) = tex { - a.push(t); - } - else{ - fine = false; - break; - } - } - if(fine == false){ - break; - } - } - - if(fine){ - Some(TexWrap {size_vec:s, col_count:col_count, row_count:row_count,texture_array:a, col_translation:col_increment, row_translation:row_increment }) - } - else { - None - } - } - - pub fn draw_textures(&self,draw: &mut Draw, translation_x:f32, translation_y:f32, scale: f32){ - let mut tex_idx = 0; - for row_idx in 0..self.row_count - { - let translate_y = translation_y+scale*row_idx as f32*self.row_translation as f32; - for col_idx in 0..self.col_count - { - let translate_x = translation_x+scale*col_idx as f32 *self.col_translation as f32; - draw.image(&self.texture_array[tex_idx]) - .blend_mode(BlendMode::NORMAL) - .scale(scale, scale) - .translate(translate_x, translate_y); - tex_idx += 1; - } - } - } - - pub fn update_textures(&mut self, gfx: &mut Graphics, image: &RgbaImage){ - if(self.col_count==1 && self.row_count==1){ - if let Err(e) = gfx.update_texture(&mut self.texture_array[0]).with_data(image).update() { - error!("{e}"); - } - }else{ - let mut tex_index = 0; - for row_index in 0..self.row_count { - let tex_start_y = row_index*self.row_translation; - let tex_height = std::cmp::min( - self.row_translation, - image.height()-tex_start_y - ); - for col_index in 0..self.col_count { - let tex_start_x = col_index*self.col_translation; - let tex_width = std::cmp::min( - self.col_translation, - image.width()-tex_start_x - ); - - let sub_img = imageops::crop_imm(image, tex_start_x, tex_start_y, tex_width, tex_height); - let my_img = sub_img.to_image(); - if let Err(e) = gfx.update_texture(&mut self.texture_array[tex_index]).with_data(my_img.as_ref()).update() { - error!("{e}"); - } - tex_index += 1; - } - } - } - } - - pub fn get_texture_at_uv(&self, ua:f64, va:f64)->TextureResponse { - let xa = ua as f64*self.width()as f64; - let ya = va as f64*self.height()as f64; - - let v = (va).max(0.0).min(1.0)as f64; - let u = ua.max(0.0).min(1.0)as f64; - let x = u*self.width()as f64; - let y = v*self.height()as f64; - - let x_idx = (x /self.col_translation as f64).floor() as i32; - let y_idx = (y /self.row_translation as f64).floor() as i32; - let tex_idx = (y_idx*self.col_count as i32+x_idx).min((self.texture_array.len() as i32 -1)); - let my_tex = &self.texture_array[tex_idx as usize]; - - let tex_left = x_idx*self.col_translation as i32; - let tex_top = y_idx*self.row_translation as i32; - - //the current texture might be smaller than the set translation. (Last element on x or y axis) - let tex_right_next = tex_left+my_tex.width() as i32; - let tex_bottom_next = tex_top+my_tex.height() as i32; - let tex_right = tex_right_next; - let tex_bottom = tex_bottom_next; - let u_scale = my_tex.width() as f64/self.width() as f64; - let v_scale = my_tex.height() as f64/self.height() as f64; - - - let u_tex_left_global = tex_left as f64/self.width() as f64; - let v_tex_top_global = tex_top as f64/self.height() as f64; - - let u_offset = (xa-tex_left as f64)/my_tex.width()as f64; - let v_offset = (ya-tex_top as f64)/my_tex.height()as f64; - - let u_tex_right = tex_right as f64 /self.width()as f64; - let v_tex_bottom = tex_bottom as f64 /self.height()as f64; - let u_tex_next_right_global = tex_right_next as f64 /self.width()as f64; - let v_tex_next_bottom_global = tex_bottom_next as f64 /self.height()as f64; - - - - TextureResponse {texture: my_tex, - u_tex_left_global, - v_tex_top_global, - u_offset_texture:u_offset, - v_offset_texture:v_offset, - u_tex_right_global:u_tex_right, - v_tex_bottom_global:v_tex_bottom, - u_tex_next_right_global, - v_tex_next_bottom_global, - u_scale:u_scale, - v_scale:v_scale } - } - - pub fn size(&self)->(f32,f32){ - return self.size_vec; - } - - pub fn width(&self)-> f32 { - return self.size_vec.0; - } - - pub fn height(&self)-> f32 { - return self.size_vec.1; - } -} /// The state of the application #[derive(AppState)] @@ -370,7 +125,7 @@ impl Default for OculanteState { cursor: Default::default(), cursor_relative: Default::default(), sampled_color: [0., 0., 0., 0.], - player: Player::new(tx_channel.0.clone(), 20, 16384), + player: Player::new(tx_channel.0.clone(), 20), texture_channel: tx_channel, message_channel: mpsc::channel(), load_channel: mpsc::channel(), diff --git a/src/main.rs b/src/main.rs index 848f9684..9c94ea37 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,6 +35,7 @@ mod image_loader; use appstate::*; #[cfg(not(feature = "file_open"))] mod filebrowser; +mod texture_wrapper; pub mod ktx2_loader; // mod events; @@ -218,8 +219,7 @@ fn init(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins) -> OculanteSta state.player = Player::new( state.texture_channel.0.clone(), - state.persistent_settings.max_cache, - gfx.limits().max_texture_size, + state.persistent_settings.max_cache ); debug!("Image is: {:?}", maybe_img_location); diff --git a/src/texture_wrapper.rs b/src/texture_wrapper.rs new file mode 100644 index 00000000..a14d9a50 --- /dev/null +++ b/src/texture_wrapper.rs @@ -0,0 +1,256 @@ +use notan::draw::*; + +use crate::Draw; +use image::imageops; + + +use image::RgbaImage; + +use notan::prelude::{Graphics, Texture, TextureFilter, BlendMode}; +use log::error; + +pub struct TexWrap{ + texture_array:Vec, + pub col_count:u32, + pub row_count:u32, + pub col_translation:u32, + pub row_translation:u32, + pub size_vec:(f32,f32) // The whole Texture Array size +} + +pub struct TextureResponse<'a>{ + pub texture: &'a Texture, + pub u_tex_left_global : f64, + pub v_tex_top_global : f64, + pub u_offset_texture : f64, + pub v_offset_texture : f64, + pub u_tex_right_global : f64, + pub v_tex_bottom_global : f64, + pub u_tex_next_right_global : f64, + pub v_tex_next_bottom_global : f64, + pub u_scale:f64, + pub v_scale:f64 +} + +impl TexWrap{ + /*pub fn new(texture: Texture) -> Self{ + let s = texture.size(); + TexWrap { tex: texture, size_vec:s } + }*/ + + //pub fn from_rgba_image_premult(gfx: &mut Graphics, linear_mag_filter: bool, image: &RgbaImage) -> Option{} + + pub fn from_rgbaimage(gfx: &mut Graphics, linear_mag_filter: bool, image: &RgbaImage) -> Option{ + Self::gen_from_rgbaimage(gfx, linear_mag_filter, image, Self::gen_texture_standard) + } + + pub fn from_rgbaimage_premult(gfx: &mut Graphics, linear_mag_filter: bool, image: &RgbaImage) -> Option{ + Self::gen_from_rgbaimage(gfx, linear_mag_filter, image, Self::gen_texture_premult) + } + + fn gen_texture_standard(gfx: &mut Graphics, bytes:&[u8], width:u32, height:u32, linear_mag_filter:bool)-> Option + { + gfx.create_texture() + .from_bytes(bytes, width, height) + .with_mipmaps(true) + // .with_format(notan::prelude::TextureFormat::SRgba8) + // .with_premultiplied_alpha() + .with_filter( + TextureFilter::Linear, + if linear_mag_filter { + TextureFilter::Linear + } else { + TextureFilter::Nearest + }, + ) + // .with_wrap(TextureWrap::Clamp, TextureWrap::Clamp) + .build() + .ok() + } + + fn gen_texture_premult(gfx: &mut Graphics, bytes:&[u8], width:u32, height:u32, linear_mag_filter:bool)-> Option + { + gfx.create_texture() + .from_bytes(bytes, width, height) + .with_premultiplied_alpha() + .with_mipmaps(true) + // .with_format(notan::prelude::TextureFormat::SRgba8) + // .with_premultiplied_alpha() + .with_filter( + TextureFilter::Linear, + if linear_mag_filter { + TextureFilter::Linear + } else { + TextureFilter::Nearest + }, + ) + // .with_wrap(TextureWrap::Clamp, TextureWrap::Clamp) + .build() + .ok() + } + + fn gen_from_rgbaimage(gfx: &mut Graphics, linear_mag_filter: bool, image: &RgbaImage, fuuun: fn (&mut Graphics, &[u8], u32, u32, bool)-> Option) -> Option{ + + let im_w = image.width(); + let im_h = image.height(); + let s = (im_w as f32, im_h as f32); + let max_texture_size = gfx.limits().max_texture_size; //128;// + let col_count = (im_w as f32/max_texture_size as f32).ceil() as u32; + let row_count = (im_h as f32/max_texture_size as f32).ceil() as u32; + + let mut a:Vec = Vec::new(); + let row_increment = std::cmp::min(max_texture_size, im_h); + let col_increment = std::cmp::min(max_texture_size, im_w); + let mut fine = true; + + for row_index in 0..row_count { + let tex_start_y = row_index*row_increment; + let tex_height = std::cmp::min( + row_increment, + im_h-tex_start_y + ); + for col_index in 0..col_count { + let tex_start_x = col_index*col_increment; + let tex_width = std::cmp::min( + col_increment, + im_w-tex_start_x + ); + + let sub_img = imageops::crop_imm(image, tex_start_x, tex_start_y, tex_width, tex_height); + let my_img = sub_img.to_image(); + let tex = fuuun(gfx, my_img.as_ref(), my_img.width(), my_img.height(), linear_mag_filter); + + if let Some(t) = tex { + a.push(t); + } + else{ + a.clear(); + fine = false; + break; + } + } + if fine == false { + break; + } + } + + if fine { + Some(TexWrap {size_vec:s, col_count:col_count, row_count:row_count,texture_array:a, col_translation:col_increment, row_translation:row_increment }) + } + else { + None + } + } + + pub fn draw_textures(&self,draw: &mut Draw, translation_x:f32, translation_y:f32, scale: f32){ + let mut tex_idx = 0; + for row_idx in 0..self.row_count + { + let translate_y = translation_y+scale*row_idx as f32*self.row_translation as f32; + for col_idx in 0..self.col_count + { + let translate_x = translation_x+scale*col_idx as f32 *self.col_translation as f32; + draw.image(&self.texture_array[tex_idx]) + .blend_mode(BlendMode::NORMAL) + .scale(scale, scale) + .translate(translate_x, translate_y); + tex_idx += 1; + } + } + } + + pub fn update_textures(&mut self, gfx: &mut Graphics, image: &RgbaImage){ + if self.col_count==1 && self.row_count==1 { + if let Err(e) = gfx.update_texture(&mut self.texture_array[0]).with_data(image).update() { + error!("{e}"); + } + }else{ + let mut tex_index = 0; + for row_index in 0..self.row_count { + let tex_start_y = row_index*self.row_translation; + let tex_height = std::cmp::min( + self.row_translation, + image.height()-tex_start_y + ); + for col_index in 0..self.col_count { + let tex_start_x = col_index*self.col_translation; + let tex_width = std::cmp::min( + self.col_translation, + image.width()-tex_start_x + ); + + let sub_img = imageops::crop_imm(image, tex_start_x, tex_start_y, tex_width, tex_height); + let my_img = sub_img.to_image(); + if let Err(e) = gfx.update_texture(&mut self.texture_array[tex_index]).with_data(my_img.as_ref()).update() { + error!("{e}"); + } + tex_index += 1; + } + } + } + } + + pub fn get_texture_at_uv(&self, ua:f64, va:f64)->TextureResponse { + let xa = ua as f64*self.width()as f64; + let ya = va as f64*self.height()as f64; + + let v = (va).max(0.0).min(1.0)as f64; + let u = ua.max(0.0).min(1.0)as f64; + let x = u*self.width()as f64; + let y = v*self.height()as f64; + + let x_idx = (x /self.col_translation as f64).floor() as i32; + let y_idx = (y /self.row_translation as f64).floor() as i32; + let tex_idx = (y_idx*self.col_count as i32+x_idx).min(self.texture_array.len() as i32 -1); + let my_tex = &self.texture_array[tex_idx as usize]; + + let tex_left = x_idx*self.col_translation as i32; + let tex_top = y_idx*self.row_translation as i32; + + //the current texture might be smaller than the set translation. (Last element on x or y axis) + let tex_right_next = tex_left+my_tex.width() as i32; + let tex_bottom_next = tex_top+my_tex.height() as i32; + let tex_right = tex_right_next; + let tex_bottom = tex_bottom_next; + let u_scale = my_tex.width() as f64/self.width() as f64; + let v_scale = my_tex.height() as f64/self.height() as f64; + + + let u_tex_left_global = tex_left as f64/self.width() as f64; + let v_tex_top_global = tex_top as f64/self.height() as f64; + + let u_offset = (xa-tex_left as f64)/my_tex.width()as f64; + let v_offset = (ya-tex_top as f64)/my_tex.height()as f64; + + let u_tex_right = tex_right as f64 /self.width()as f64; + let v_tex_bottom = tex_bottom as f64 /self.height()as f64; + let u_tex_next_right_global = tex_right_next as f64 /self.width()as f64; + let v_tex_next_bottom_global = tex_bottom_next as f64 /self.height()as f64; + + + + TextureResponse {texture: my_tex, + u_tex_left_global, + v_tex_top_global, + u_offset_texture:u_offset, + v_offset_texture:v_offset, + u_tex_right_global:u_tex_right, + v_tex_bottom_global:v_tex_bottom, + u_tex_next_right_global, + v_tex_next_bottom_global, + u_scale:u_scale, + v_scale:v_scale } + } + + pub fn size(&self)->(f32,f32){ + return self.size_vec; + } + + pub fn width(&self)-> f32 { + return self.size_vec.0; + } + + pub fn height(&self)-> f32 { + return self.size_vec.1; + } +} \ No newline at end of file diff --git a/src/ui.rs b/src/ui.rs index 1539aad6..af099e8d 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -26,9 +26,9 @@ use log::{debug, error, info}; use mouse_position::mouse_position::Mouse; use notan::{ egui::{self, *}, - prelude::{App, Graphics, BlendMode}, + prelude::{App, Graphics}, }; -use notan::draw::*; + use std::{collections::BTreeSet, ops::RangeInclusive, path::PathBuf, time::Instant}; use strum::IntoEnumIterator; const PANEL_WIDTH: f32 = 240.0; @@ -358,7 +358,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { let mut curr_ui_curs = base_ui_curs; //our start position let mut counter_v = 0; //Safety measure... - while(curr_cursor_v, pub stop_sender: Sender<()>, pub cache: Cache, - pub max_texture_size: u32, watcher: HashMap, } impl Player { /// Create a new Player - pub fn new(image_sender: Sender, cache_size: usize, max_texture_size: u32) -> Player { + pub fn new(image_sender: Sender, cache_size: usize) -> Player { let (stop_sender, _): (Sender<()>, Receiver<()>) = mpsc::channel(); Player { image_sender, @@ -201,7 +197,6 @@ impl Player { data: Default::default(), cache_size, }, - max_texture_size, watcher: Default::default(), } } @@ -250,7 +245,6 @@ impl Player { self.image_sender.clone(), message_sender, stop_receiver, - self.max_texture_size, forced_frame_source, ); @@ -275,7 +269,6 @@ pub fn send_image_threaded( texture_sender: Sender, message_sender: Sender, stop_receiver: Receiver<()>, - max_texture_size: u32, forced_frame_source: Option, ) { let loc = img_location.to_owned(); From 7658e89f8c065ff76b33bac6a88188f47690bf41 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 22 Sep 2024 11:03:45 +0200 Subject: [PATCH 17/29] Working on simpler tiling rendering --- Cargo.toml | 4 +- src/texture_wrapper.rs | 94 ++++++++++++++++++++++++++++++- src/ui.rs | 125 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 208 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 40b909dd..07bc0af5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -133,6 +133,6 @@ opt-level = 3 panic = "abort" [profile.dev] -debug = false +debug = true incremental = true -opt-level = 1 +opt-level = 0 diff --git a/src/texture_wrapper.rs b/src/texture_wrapper.rs index b4dc18f8..628065b4 100644 --- a/src/texture_wrapper.rs +++ b/src/texture_wrapper.rs @@ -22,7 +22,7 @@ pub struct TexWrap{ pub struct TextureResponse<'a>{ pub texture: &'a Texture, pub u_tex_left_global : f64, - pub v_tex_top_global : f64, + pub v_tex_top_global : f64, pub u_offset_texture : f64, pub v_offset_texture : f64, pub u_tex_right_global : f64, @@ -33,6 +33,36 @@ pub struct TextureResponse<'a>{ pub v_scale:f64 } +pub struct TextureResponse2<'a>{ + pub texture: &'a Texture, + pub u_tex_left_global : f64, + pub v_tex_top_global : f64, + pub u_tex_right_global : f64, + pub v_tex_bottom_global : f64, + + pub x_offset_texture: i32, + pub y_offset_texture: i32, + + pub texture_width:i32, + pub texture_height:i32, + + pub x_tex_left_global : i32, + pub y_tex_top_global : i32, + pub x_tex_right_global : i32, + pub y_tex_bottom_global : i32, + + pub x_tex_right_local : i32, + pub y_tex_bottom_local : i32, + + pub u_offset_texture : f64, + pub v_offset_texture : f64, + + pub u_tex_next_right_global : f64, + pub v_tex_next_bottom_global : f64, + pub u_scale:f64, + pub v_scale:f64 +} + impl TexWrap{ /*pub fn new(texture: Texture) -> Self{ let s = texture.size(); @@ -199,6 +229,68 @@ impl TexWrap{ } } + pub fn get_texture_at_xy(&self, xa:i32, ya:i32)->TextureResponse2{ + let x = xa.max(0).min(self.width() as i32-1); + let y = ya.max(0).min(self.height() as i32-1); + + let x_idx = (x /self.col_translation as i32); + let y_idx = (y /self.row_translation as i32); + let tex_idx = (y_idx*self.col_count as i32+x_idx).min(self.texture_array.len() as i32 -1); + let my_tex = &self.texture_array[tex_idx as usize]; + + let tex_left = x_idx*self.col_translation as i32; + let tex_top = y_idx*self.row_translation as i32; + let tex_right = tex_left+self.col_translation as i32-1; + let tex_bottom = tex_top+self.row_translation as i32-1; + let tex_right_next = tex_right+1; + let tex_bottom_next = tex_bottom+1; + + let u_tex_left_global = tex_left as f64/self.width() as f64; + let v_tex_top_global = tex_top as f64/self.height() as f64; + + let x_offset_texture = xa-tex_left; + let y_offset_texture = ya-tex_top; + + let u_offset = (xa as f64-tex_left as f64)/my_tex.width()as f64; + let v_offset = (ya as f64-tex_top as f64)/my_tex.height()as f64; + + let u_tex_right = tex_right as f64 /self.width()as f64; + let v_tex_bottom = tex_bottom as f64 /self.height()as f64; + + + let u_tex_next_right_global = tex_right_next as f64 /self.width()as f64; + let v_tex_next_bottom_global = tex_bottom_next as f64 /self.height()as f64; + + let u_scale = my_tex.width() as f64/self.width() as f64; + let v_scale = my_tex.height() as f64/self.height() as f64; + + TextureResponse2 {texture: my_tex, + u_tex_left_global, + v_tex_top_global, + x_offset_texture: x_offset_texture, + y_offset_texture: y_offset_texture, + + texture_width: self.col_translation as i32, + texture_height: self.row_translation as i32, + + x_tex_left_global: tex_left, + y_tex_top_global: tex_top, + x_tex_right_global: tex_right, + y_tex_bottom_global: tex_bottom, + + x_tex_right_local: self.col_translation as i32-1, + y_tex_bottom_local: self.row_translation as i32-1, + + u_offset_texture:u_offset, + v_offset_texture:v_offset, + u_tex_right_global:u_tex_right, + v_tex_bottom_global:v_tex_bottom, + u_tex_next_right_global, + v_tex_next_bottom_global, + u_scale:u_scale, + v_scale:v_scale } + } + pub fn get_texture_at_uv(&self, ua:f64, va:f64)->TextureResponse { let xa = ua as f64*self.width()as f64; let ya = va as f64*self.height()as f64; diff --git a/src/ui.rs b/src/ui.rs index 185ee096..f1cbb7af 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -32,6 +32,7 @@ use notan::{ egui::{self, *}, prelude::{App, Graphics}, }; +use wgpu::TextureUsages; use std::{ collections::BTreeSet, ops::RangeInclusive, @@ -530,6 +531,10 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { (state.cursor_relative.y as f64 / state.image_geometry.dimensions.1 as f64), ); + let xy_center = ((texture.width() as f64*uv_center.0) as i32, (texture.height() as f64*uv_center.1) as i32); //(16384,1024);// + + + egui::Grid::new("info") .num_columns(2) .show(ui, |ui| { @@ -585,9 +590,113 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { }); + // make sure aspect ratio is compensated for the square preview let ratio = texture.size().0 / texture.size().1; let uv_size = (scale, scale * ratio as f64); + let xy_size = ((texture.width()as f64*uv_size.0) as i32, + (texture.height()as f64*uv_size.1) as i32); + let sc1 = xy_size.0 as f64 / desired_width; + println!("image x:{0} y:{1} w:{2} h:{3}", xy_center.0, xy_center.1, xy_size.0, xy_size.1); + + //coordinates of the image-view + let mut bbox_tl = egui::pos2(f32::MAX, f32::MAX); + let mut bbox_br = egui::pos2(f32::MIN, f32::MIN); + + //Ui position to start at + let base_ui_curs = nalgebra::Vector2::new(ui.cursor().min.x as f64, ui.cursor().min.y as f64); + let mut curr_ui_curs = base_ui_curs; //our start position + + //Loop control variables + let x_e = (xy_center.0+xy_size.0)-1 as i32; + let mut y_c = xy_center.1-xy_size.1; + let y_e = (xy_center.1+xy_size.1)-1 as i32; + + while(y_c= texture.width()-1.0f32){ + println!("End X!"); + x_c = x_e; + extra_width.0 = (x_e-curr_tex_response.x_tex_right_global-1).max(0); + } +// + if(curr_tex_response.y_tex_bottom_global as f32>= texture.height()-1.0f32){ + println!("End Y!"); + y_c = y_e; + y_c_i = 0; + extra_width.1 = (y_e-curr_tex_response.y_tex_bottom_global-1).max(0); + } + + println!("{0}, {1}, {2}, {3}", y_c, y_e, my_height, my_width); + + //End of texture, display width + let mut curr_tex_x_end = i32::min(curr_tex_response.x_tex_right_global, x_e); + let mut curr_tex_y_end = i32::min(curr_tex_response.y_tex_bottom_global, y_e); + let display_width = curr_tex_x_end-curr_tex_response.x_offset_texture-curr_tex_response.x_tex_left_global+extra_width.0; + let display_height = curr_tex_y_end-curr_tex_response.y_offset_texture-curr_tex_response.y_tex_top_global+extra_width.1; +//y: 1 px fehlt in erster textur! +//x: 1 px fehlt in erster textur! + //Display size + let u_size = 0.5*display_width as f64/sc1; + let v_size = 0.5*display_height as f64/sc1; + + + let curr_ui_curs_after = curr_ui_curs+nalgebra::Vector2::new(u_size, 0.0); + + //Texture display range + let u_offset_texture_snipped = curr_tex_response.x_offset_texture as f64 / curr_tex_response.texture_width as f64; + let v_offset_texture_snipped = curr_tex_response.y_offset_texture as f64 / curr_tex_response.texture_height as f64; + + let curr_tex_u_end_texture = (curr_tex_x_end-curr_tex_response.x_tex_left_global +extra_width.0) as f64 / curr_tex_response.texture_width as f64; + let curr_tex_v_end_texture = (curr_tex_y_end-curr_tex_response.y_tex_top_global+extra_width.1) as f64 / curr_tex_response.texture_height as f64; + + + let tex_id2 = gfx.egui_register_texture(curr_tex_response.texture); + let draw_tl_32 = Pos2::new(curr_ui_curs.x as f32, curr_ui_curs.y as f32); + let draw_br_64 = curr_ui_curs_after+nalgebra::Vector2::new(0.0, v_size); + let draw_br_32 = Pos2::new(draw_br_64.x as f32, draw_br_64.y as f32); + let r_ret =egui::Rect::from_min_max(draw_tl_32, draw_br_32); + println!("{0} {1}",r_ret.width(), r_ret.height()); + + egui::Image::new(tex_id2) + .maintain_aspect_ratio(false) + + .fit_to_exact_size(egui::Vec2::new(u_size as f32, v_size as f32)) + .uv(egui::Rect::from_x_y_ranges( + u_offset_texture_snipped as f32 ..=curr_tex_u_end_texture as f32, + v_offset_texture_snipped as f32 ..=curr_tex_v_end_texture as f32, + ) + ) + .paint_at(ui, r_ret); + + + curr_ui_curs = curr_ui_curs_after; + last_v_size = v_size; + //Update coordinates for preview rectangle + bbox_tl.x = bbox_tl.x.min(r_ret.left()); + bbox_tl.y = bbox_tl.y.min(r_ret.top()); + + bbox_br.x = bbox_br.x.max(r_ret.right()); + bbox_br.y = bbox_br.y.max(r_ret.bottom()); + + } + y_c += y_c_i; + curr_ui_curs += nalgebra::Vector2::new(0.0, last_v_size); + } + let bg_color = Color32::BLACK.linear_multiply(0.5); /*let preview_rect = ui @@ -606,10 +715,9 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { .rect;*/ //Pre initialize the rectangle coordinates of the preview window - let mut bbox_tl = egui::pos2(f32::MAX, f32::MAX); - let mut bbox_br = egui::pos2(f32::MIN, f32::MIN); + - //The uv positions in the image, we iterate over + /*//The uv positions in the image, we iterate over let mut curr_cursor_v = uv_center.1 - uv_size.1; let end_cursor_u = uv_center.0 + uv_size.0; let end_cursor_v = uv_center.1 + uv_size.1; @@ -695,14 +803,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { .paint_at(ui, r_ret); - //.texture_options(TextureOptions::LINEAR) - //).rect; - - /*draw.image(&curr_tex.texture) - .blend_mode(BlendMode::NORMAL) - //.scale(u_size, scale) - .size(u_size, v_size) - .translate(curr_ui_curs.x, curr_ui_curs.y);*/ + //Update coordinates for preview rectangle bbox_tl.x = bbox_tl.x.min(r_ret.left()); @@ -717,7 +818,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { curr_ui_curs += nalgebra::Vector2::new(0.0, last_v_size); curr_cursor_v = next_tex_v_begin; - } + }*/ let preview_rect = egui::Rect::from_min_max(bbox_tl, bbox_br); From 0a109ec77166843a507485238cca42f83a067388 Mon Sep 17 00:00:00 2001 From: Simon Wezstein Date: Sun, 22 Sep 2024 21:53:59 +0200 Subject: [PATCH 18/29] Tiled info image rendering works! --- src/texture_wrapper.rs | 65 ++++++++++++++++++++-------------- src/ui.rs | 79 +++++++++++++++++++++++++----------------- 2 files changed, 86 insertions(+), 58 deletions(-) diff --git a/src/texture_wrapper.rs b/src/texture_wrapper.rs index 628065b4..5fbfe58f 100644 --- a/src/texture_wrapper.rs +++ b/src/texture_wrapper.rs @@ -35,16 +35,18 @@ pub struct TextureResponse<'a>{ pub struct TextureResponse2<'a>{ pub texture: &'a Texture, - pub u_tex_left_global : f64, - pub v_tex_top_global : f64, - pub u_tex_right_global : f64, - pub v_tex_bottom_global : f64, + //pub u_tex_left_global : f64, + //pub v_tex_top_global : f64, + //pub u_tex_right_global : f64, + //pub v_tex_bottom_global : f64, pub x_offset_texture: i32, pub y_offset_texture: i32, pub texture_width:i32, pub texture_height:i32, + pub offset_width:i32, + pub offset_height:i32, pub x_tex_left_global : i32, pub y_tex_top_global : i32, @@ -54,13 +56,13 @@ pub struct TextureResponse2<'a>{ pub x_tex_right_local : i32, pub y_tex_bottom_local : i32, - pub u_offset_texture : f64, + /*pub u_offset_texture : f64, pub v_offset_texture : f64, pub u_tex_next_right_global : f64, pub v_tex_next_bottom_global : f64, pub u_scale:f64, - pub v_scale:f64 + pub v_scale:f64*/ } impl TexWrap{ @@ -133,7 +135,7 @@ impl TexWrap{ let im_w = image.width(); let im_h = image.height(); let s = (im_w as f32, im_h as f32); - let max_texture_size = gfx.limits().max_texture_size; //128;// + let max_texture_size = 128;//gfx.limits().max_texture_size; let col_count = (im_w as f32/max_texture_size as f32).ceil() as u32; let row_count = (im_h as f32/max_texture_size as f32).ceil() as u32; @@ -230,6 +232,8 @@ impl TexWrap{ } pub fn get_texture_at_xy(&self, xa:i32, ya:i32)->TextureResponse2{ + + let x = xa.max(0).min(self.width() as i32-1); let y = ya.max(0).min(self.height() as i32-1); @@ -238,10 +242,13 @@ impl TexWrap{ let tex_idx = (y_idx*self.col_count as i32+x_idx).min(self.texture_array.len() as i32 -1); let my_tex = &self.texture_array[tex_idx as usize]; + let width = my_tex.width() as i32; + let height = my_tex.height() as i32; + let tex_left = x_idx*self.col_translation as i32; let tex_top = y_idx*self.row_translation as i32; - let tex_right = tex_left+self.col_translation as i32-1; - let tex_bottom = tex_top+self.row_translation as i32-1; + let tex_right = tex_left+width-1; + let tex_bottom = tex_top+height-1; let tex_right_next = tex_right+1; let tex_bottom_next = tex_bottom+1; @@ -251,27 +258,30 @@ impl TexWrap{ let x_offset_texture = xa-tex_left; let y_offset_texture = ya-tex_top; - let u_offset = (xa as f64-tex_left as f64)/my_tex.width()as f64; - let v_offset = (ya as f64-tex_top as f64)/my_tex.height()as f64; + let remaining_width = width- x_offset_texture; + let remaining_height = height - y_offset_texture; + + /*let u_offset = (xa as f64-tex_left as f64)/my_tex.width()as f64; + let v_offset = (ya as f64-tex_top as f64)/my_tex.height()as f64;*/ let u_tex_right = tex_right as f64 /self.width()as f64; let v_tex_bottom = tex_bottom as f64 /self.height()as f64; - let u_tex_next_right_global = tex_right_next as f64 /self.width()as f64; + /*let u_tex_next_right_global = tex_right_next as f64 /self.width()as f64; let v_tex_next_bottom_global = tex_bottom_next as f64 /self.height()as f64; let u_scale = my_tex.width() as f64/self.width() as f64; - let v_scale = my_tex.height() as f64/self.height() as f64; + let v_scale = my_tex.height() as f64/self.height() as f64;*/ TextureResponse2 {texture: my_tex, - u_tex_left_global, - v_tex_top_global, + //u_tex_left_global, + //v_tex_top_global, x_offset_texture: x_offset_texture, y_offset_texture: y_offset_texture, - texture_width: self.col_translation as i32, - texture_height: self.row_translation as i32, + texture_width: width, + texture_height: height, x_tex_left_global: tex_left, y_tex_top_global: tex_top, @@ -280,15 +290,18 @@ impl TexWrap{ x_tex_right_local: self.col_translation as i32-1, y_tex_bottom_local: self.row_translation as i32-1, - - u_offset_texture:u_offset, - v_offset_texture:v_offset, - u_tex_right_global:u_tex_right, - v_tex_bottom_global:v_tex_bottom, - u_tex_next_right_global, - v_tex_next_bottom_global, - u_scale:u_scale, - v_scale:v_scale } + offset_width: remaining_width, + offset_height: remaining_height, + + //u_offset_texture:u_offset, + //v_offset_texture:v_offset, + //u_tex_right_global:u_tex_right, + //v_tex_bottom_global:v_tex_bottom, + //u_tex_next_right_global, + //v_tex_next_bottom_global, + //u_scale:u_scale, + //v_scale:v_scale + } } pub fn get_texture_at_uv(&self, ua:f64, va:f64)->TextureResponse { diff --git a/src/ui.rs b/src/ui.rs index f1cbb7af..ebdf4d83 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -592,11 +592,12 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { // make sure aspect ratio is compensated for the square preview - let ratio = texture.size().0 / texture.size().1; - let uv_size = (scale, scale * ratio as f64); + let ratio = texture.size().0 as f64 / texture.size().1 as f64; + let uv_size = (scale, scale * ratio); let xy_size = ((texture.width()as f64*uv_size.0) as i32, (texture.height()as f64*uv_size.1) as i32); - let sc1 = xy_size.0 as f64 / desired_width; + let sc1 = (2.0*xy_size.0 as f64 / desired_width, + 2.0*xy_size.1 as f64 / desired_width); println!("image x:{0} y:{1} w:{2} h:{3}", xy_center.0, xy_center.1, xy_size.0, xy_size.1); //coordinates of the image-view @@ -608,50 +609,56 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { let mut curr_ui_curs = base_ui_curs; //our start position //Loop control variables - let x_e = (xy_center.0+xy_size.0)-1 as i32; + let x_e = (xy_center.0+xy_size.0) as i32; let mut y_c = xy_center.1-xy_size.1; - let y_e = (xy_center.1+xy_size.1)-1 as i32; + let y_e = (xy_center.1+xy_size.1) as i32; - while(y_c= texture.width()-1.0f32){ println!("End X!"); - x_c = x_e; - extra_width.0 = (x_e-curr_tex_response.x_tex_right_global-1).max(0); + x_c = x_e+1; + curr_tex_x_end += (x_e-curr_tex_response.x_tex_right_global).max(0); } // if(curr_tex_response.y_tex_bottom_global as f32>= texture.height()-1.0f32){ - println!("End Y!"); - y_c = y_e; - y_c_i = 0; - extra_width.1 = (y_e-curr_tex_response.y_tex_bottom_global-1).max(0); + println!("End Y!"); + y_c_i = y_e-y_c+1; + curr_tex_y_end += (y_e-curr_tex_response.y_tex_bottom_global).max(0); } + println!("curr_tex_x_end {0} curr_tex_y_end {1} ", curr_tex_x_end, curr_tex_y_end); - println!("{0}, {1}, {2}, {3}", y_c, y_e, my_height, my_width); + + + //End of texture, display width + let display_width = curr_tex_x_end-curr_tex_response.x_offset_texture-curr_tex_response.x_tex_left_global+1; + let display_height = curr_tex_y_end-curr_tex_response.y_offset_texture-curr_tex_response.y_tex_top_global+1; + + - //End of texture, display width - let mut curr_tex_x_end = i32::min(curr_tex_response.x_tex_right_global, x_e); - let mut curr_tex_y_end = i32::min(curr_tex_response.y_tex_bottom_global, y_e); - let display_width = curr_tex_x_end-curr_tex_response.x_offset_texture-curr_tex_response.x_tex_left_global+extra_width.0; - let display_height = curr_tex_y_end-curr_tex_response.y_offset_texture-curr_tex_response.y_tex_top_global+extra_width.1; -//y: 1 px fehlt in erster textur! -//x: 1 px fehlt in erster textur! //Display size - let u_size = 0.5*display_width as f64/sc1; - let v_size = 0.5*display_height as f64/sc1; + let u_size = display_width as f64/sc1.0; + let v_size = display_height as f64/sc1.1; let curr_ui_curs_after = curr_ui_curs+nalgebra::Vector2::new(u_size, 0.0); @@ -660,8 +667,16 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { let u_offset_texture_snipped = curr_tex_response.x_offset_texture as f64 / curr_tex_response.texture_width as f64; let v_offset_texture_snipped = curr_tex_response.y_offset_texture as f64 / curr_tex_response.texture_height as f64; - let curr_tex_u_end_texture = (curr_tex_x_end-curr_tex_response.x_tex_left_global +extra_width.0) as f64 / curr_tex_response.texture_width as f64; - let curr_tex_v_end_texture = (curr_tex_y_end-curr_tex_response.y_tex_top_global+extra_width.1) as f64 / curr_tex_response.texture_height as f64; + + + + let curr_tex_u_end_texture = (curr_tex_x_end-curr_tex_response.x_tex_left_global+1) as f64 / curr_tex_response.texture_width as f64; + let curr_tex_v_end_texture = (curr_tex_y_end-curr_tex_response.y_tex_top_global+1) as f64 / curr_tex_response.texture_height as f64; + + println!("Using Texture x_c {0} y_c {1} {2} {3} xe {4} ye {5} tex bo {6} wx {7} wy {8} u-b{9} v-b{10} u-e{11} v-b{12} y_c after {13}]", + x_c_o, y_c_o, curr_tex_x_end, curr_tex_y_end, x_e, y_e, curr_tex_response.y_tex_bottom_global, + display_width, display_height, u_offset_texture_snipped, v_offset_texture_snipped, curr_tex_u_end_texture, + curr_tex_v_end_texture, y_c_o+y_c_i); let tex_id2 = gfx.egui_register_texture(curr_tex_response.texture); @@ -669,7 +684,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { let draw_br_64 = curr_ui_curs_after+nalgebra::Vector2::new(0.0, v_size); let draw_br_32 = Pos2::new(draw_br_64.x as f32, draw_br_64.y as f32); let r_ret =egui::Rect::from_min_max(draw_tl_32, draw_br_32); - println!("{0} {1}",r_ret.width(), r_ret.height()); + egui::Image::new(tex_id2) .maintain_aspect_ratio(false) From 5b368e36d4fab15d5d9fc8226061ff90cc773c43 Mon Sep 17 00:00:00 2001 From: Simon Wezstein Date: Sun, 22 Sep 2024 21:57:33 +0200 Subject: [PATCH 19/29] Refactoring pt.1 --- src/ui.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/ui.rs b/src/ui.rs index ebdf4d83..4ef7c998 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -629,30 +629,32 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { x_c += curr_tex_response.offset_width; - let mut curr_tex_x_end = i32::min(curr_tex_response.x_tex_right_global, x_e); - let mut curr_tex_y_end = i32::min(curr_tex_response.y_tex_bottom_global, y_e); + //let mut curr_tex_x_end = ; + //let mut curr_tex_y_end = i32::min(curr_tex_response.y_tex_bottom_global, y_e); - print!("curr_tex_x_end {0} curr_tex_y_end {1} ", curr_tex_x_end, curr_tex_y_end); + let mut cutt_tex_end = nalgebra::Vector2::new(i32::min(curr_tex_response.x_tex_right_global, x_e), i32::min(curr_tex_response.y_tex_bottom_global, y_e)); + + print!("curr_tex_x_end {0} curr_tex_y_end {1} ", cutt_tex_end.x, cutt_tex_end.y); //Handling positive overflow if(curr_tex_response.x_tex_right_global as f32>= texture.width()-1.0f32){ println!("End X!"); x_c = x_e+1; - curr_tex_x_end += (x_e-curr_tex_response.x_tex_right_global).max(0); + cutt_tex_end.x += (x_e-curr_tex_response.x_tex_right_global).max(0); } // if(curr_tex_response.y_tex_bottom_global as f32>= texture.height()-1.0f32){ println!("End Y!"); y_c_i = y_e-y_c+1; - curr_tex_y_end += (y_e-curr_tex_response.y_tex_bottom_global).max(0); + cutt_tex_end.y += (y_e-curr_tex_response.y_tex_bottom_global).max(0); } - println!("curr_tex_x_end {0} curr_tex_y_end {1} ", curr_tex_x_end, curr_tex_y_end); + println!("curr_tex_x_end {0} curr_tex_y_end {1} ", cutt_tex_end.x, cutt_tex_end.y); //End of texture, display width - let display_width = curr_tex_x_end-curr_tex_response.x_offset_texture-curr_tex_response.x_tex_left_global+1; - let display_height = curr_tex_y_end-curr_tex_response.y_offset_texture-curr_tex_response.y_tex_top_global+1; + let display_width = cutt_tex_end.x-curr_tex_response.x_offset_texture-curr_tex_response.x_tex_left_global+1; + let display_height = cutt_tex_end.y-curr_tex_response.y_offset_texture-curr_tex_response.y_tex_top_global+1; @@ -670,11 +672,11 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { - let curr_tex_u_end_texture = (curr_tex_x_end-curr_tex_response.x_tex_left_global+1) as f64 / curr_tex_response.texture_width as f64; - let curr_tex_v_end_texture = (curr_tex_y_end-curr_tex_response.y_tex_top_global+1) as f64 / curr_tex_response.texture_height as f64; + let curr_tex_u_end_texture = (cutt_tex_end.x-curr_tex_response.x_tex_left_global+1) as f64 / curr_tex_response.texture_width as f64; + let curr_tex_v_end_texture = (cutt_tex_end.y-curr_tex_response.y_tex_top_global+1) as f64 / curr_tex_response.texture_height as f64; println!("Using Texture x_c {0} y_c {1} {2} {3} xe {4} ye {5} tex bo {6} wx {7} wy {8} u-b{9} v-b{10} u-e{11} v-b{12} y_c after {13}]", - x_c_o, y_c_o, curr_tex_x_end, curr_tex_y_end, x_e, y_e, curr_tex_response.y_tex_bottom_global, + x_c_o, y_c_o, cutt_tex_end.x, cutt_tex_end.y, x_e, y_e, curr_tex_response.y_tex_bottom_global, display_width, display_height, u_offset_texture_snipped, v_offset_texture_snipped, curr_tex_u_end_texture, curr_tex_v_end_texture, y_c_o+y_c_i); From 4534d8daddfabde5c5155f0a59c08856d9999a79 Mon Sep 17 00:00:00 2001 From: Simon Wezstein Date: Sun, 22 Sep 2024 22:07:12 +0200 Subject: [PATCH 20/29] Refactoring pt.2 --- src/ui.rs | 53 +++++++++++++++++++++++------------------------------ 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/src/ui.rs b/src/ui.rs index 4ef7c998..557cef05 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -628,62 +628,55 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { print!("xc {0} yc {1} ", x_c, y_c); x_c += curr_tex_response.offset_width; + //Handling last texture in a row or col + let mut curr_tex_end = nalgebra::Vector2::new(i32::min(curr_tex_response.x_tex_right_global, x_e), i32::min(curr_tex_response.y_tex_bottom_global, y_e)); - //let mut curr_tex_x_end = ; - //let mut curr_tex_y_end = i32::min(curr_tex_response.y_tex_bottom_global, y_e); - - let mut cutt_tex_end = nalgebra::Vector2::new(i32::min(curr_tex_response.x_tex_right_global, x_e), i32::min(curr_tex_response.y_tex_bottom_global, y_e)); - - print!("curr_tex_x_end {0} curr_tex_y_end {1} ", cutt_tex_end.x, cutt_tex_end.y); + print!("curr_tex_x_end {0} curr_tex_y_end {1} ", curr_tex_end.x, curr_tex_end.y); //Handling positive overflow if(curr_tex_response.x_tex_right_global as f32>= texture.width()-1.0f32){ println!("End X!"); x_c = x_e+1; - cutt_tex_end.x += (x_e-curr_tex_response.x_tex_right_global).max(0); + curr_tex_end.x += (x_e-curr_tex_response.x_tex_right_global).max(0); } // if(curr_tex_response.y_tex_bottom_global as f32>= texture.height()-1.0f32){ println!("End Y!"); y_c_i = y_e-y_c+1; - cutt_tex_end.y += (y_e-curr_tex_response.y_tex_bottom_global).max(0); + curr_tex_end.y += (y_e-curr_tex_response.y_tex_bottom_global).max(0); } - println!("curr_tex_x_end {0} curr_tex_y_end {1} ", cutt_tex_end.x, cutt_tex_end.y); + println!("curr_tex_x_end {0} curr_tex_y_end {1} ", curr_tex_end.x, curr_tex_end.y); - //End of texture, display width - let display_width = cutt_tex_end.x-curr_tex_response.x_offset_texture-curr_tex_response.x_tex_left_global+1; - let display_height = cutt_tex_end.y-curr_tex_response.y_offset_texture-curr_tex_response.y_tex_top_global+1; + //End of texture, display width + let tile_size = nalgebra::Vector2::new(curr_tex_end.x-curr_tex_response.x_offset_texture-curr_tex_response.x_tex_left_global+1, + curr_tex_end.y-curr_tex_response.y_offset_texture-curr_tex_response.y_tex_top_global+1); //Display size - let u_size = display_width as f64/sc1.0; - let v_size = display_height as f64/sc1.1; + let display_size = nalgebra::Vector2::new(tile_size.x as f64/sc1.0,tile_size.y as f64/sc1.1); - let curr_ui_curs_after = curr_ui_curs+nalgebra::Vector2::new(u_size, 0.0); + let curr_ui_curs_after = curr_ui_curs+nalgebra::Vector2::new(display_size.x, 0.0); //Texture display range - let u_offset_texture_snipped = curr_tex_response.x_offset_texture as f64 / curr_tex_response.texture_width as f64; - let v_offset_texture_snipped = curr_tex_response.y_offset_texture as f64 / curr_tex_response.texture_height as f64; - - - + let uv_start = nalgebra::Vector2::new(curr_tex_response.x_offset_texture as f64 / curr_tex_response.texture_width as f64, + curr_tex_response.y_offset_texture as f64 / curr_tex_response.texture_height as f64); - let curr_tex_u_end_texture = (cutt_tex_end.x-curr_tex_response.x_tex_left_global+1) as f64 / curr_tex_response.texture_width as f64; - let curr_tex_v_end_texture = (cutt_tex_end.y-curr_tex_response.y_tex_top_global+1) as f64 / curr_tex_response.texture_height as f64; + let uv_end = nalgebra::Vector2::new((curr_tex_end.x-curr_tex_response.x_tex_left_global+1) as f64 / curr_tex_response.texture_width as f64, + (curr_tex_end.y-curr_tex_response.y_tex_top_global+1) as f64 / curr_tex_response.texture_height as f64); println!("Using Texture x_c {0} y_c {1} {2} {3} xe {4} ye {5} tex bo {6} wx {7} wy {8} u-b{9} v-b{10} u-e{11} v-b{12} y_c after {13}]", - x_c_o, y_c_o, cutt_tex_end.x, cutt_tex_end.y, x_e, y_e, curr_tex_response.y_tex_bottom_global, - display_width, display_height, u_offset_texture_snipped, v_offset_texture_snipped, curr_tex_u_end_texture, - curr_tex_v_end_texture, y_c_o+y_c_i); + x_c_o, y_c_o, curr_tex_end.x, curr_tex_end.y, x_e, y_e, curr_tex_response.y_tex_bottom_global, + tile_size.x, tile_size.y, uv_start.x, uv_start.y, uv_end.x, + uv_end.y, y_c_o+y_c_i); let tex_id2 = gfx.egui_register_texture(curr_tex_response.texture); let draw_tl_32 = Pos2::new(curr_ui_curs.x as f32, curr_ui_curs.y as f32); - let draw_br_64 = curr_ui_curs_after+nalgebra::Vector2::new(0.0, v_size); + let draw_br_64 = curr_ui_curs_after+nalgebra::Vector2::new(0.0, display_size.y); let draw_br_32 = Pos2::new(draw_br_64.x as f32, draw_br_64.y as f32); let r_ret =egui::Rect::from_min_max(draw_tl_32, draw_br_32); @@ -691,17 +684,17 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { egui::Image::new(tex_id2) .maintain_aspect_ratio(false) - .fit_to_exact_size(egui::Vec2::new(u_size as f32, v_size as f32)) + .fit_to_exact_size(egui::Vec2::new(display_size.x as f32, display_size.y as f32)) .uv(egui::Rect::from_x_y_ranges( - u_offset_texture_snipped as f32 ..=curr_tex_u_end_texture as f32, - v_offset_texture_snipped as f32 ..=curr_tex_v_end_texture as f32, + uv_start.x as f32 ..=uv_end.x as f32, + uv_start.y as f32 ..=uv_end.y as f32, ) ) .paint_at(ui, r_ret); curr_ui_curs = curr_ui_curs_after; - last_v_size = v_size; + last_v_size = display_size.y; //Update coordinates for preview rectangle bbox_tl.x = bbox_tl.x.min(r_ret.left()); bbox_tl.y = bbox_tl.y.min(r_ret.top()); From f2f35da1402d67c1d0be051939d776d64f1c2832 Mon Sep 17 00:00:00 2001 From: Simon Wezstein Date: Sun, 22 Sep 2024 22:17:51 +0200 Subject: [PATCH 21/29] Refactoring pt.3 --- src/ui.rs | 163 +++++------------------------------------------------- 1 file changed, 14 insertions(+), 149 deletions(-) diff --git a/src/ui.rs b/src/ui.rs index 557cef05..a3a2c79d 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -617,7 +617,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { let mut y_c_i = 0; let mut x_c = xy_center.0-xy_size.0; curr_ui_curs.x = base_ui_curs.x; - let mut last_v_size: f64 = 0.0; + let mut last_display_size_y: f64 = 0.0; while(x_c<=x_e){ let curr_tex_response = texture.get_texture_at_xy(x_c as i32, y_c as i32); let x_c_o = x_c; @@ -635,31 +635,22 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { //Handling positive overflow if(curr_tex_response.x_tex_right_global as f32>= texture.width()-1.0f32){ - println!("End X!"); x_c = x_e+1; curr_tex_end.x += (x_e-curr_tex_response.x_tex_right_global).max(0); } -// + if(curr_tex_response.y_tex_bottom_global as f32>= texture.height()-1.0f32){ - println!("End Y!"); y_c_i = y_e-y_c+1; curr_tex_end.y += (y_e-curr_tex_response.y_tex_bottom_global).max(0); } - println!("curr_tex_x_end {0} curr_tex_y_end {1} ", curr_tex_end.x, curr_tex_end.y); - - + println!("curr_tex_x_end {0} curr_tex_y_end {1} ", curr_tex_end.x, curr_tex_end.y); //End of texture, display width let tile_size = nalgebra::Vector2::new(curr_tex_end.x-curr_tex_response.x_offset_texture-curr_tex_response.x_tex_left_global+1, - curr_tex_end.y-curr_tex_response.y_offset_texture-curr_tex_response.y_tex_top_global+1); - - + curr_tex_end.y-curr_tex_response.y_offset_texture-curr_tex_response.y_tex_top_global+1); //Display size - let display_size = nalgebra::Vector2::new(tile_size.x as f64/sc1.0,tile_size.y as f64/sc1.1); - - - let curr_ui_curs_after = curr_ui_curs+nalgebra::Vector2::new(display_size.x, 0.0); + let display_size = nalgebra::Vector2::new(tile_size.x as f64/sc1.0,tile_size.y as f64/sc1.1); //Texture display range let uv_start = nalgebra::Vector2::new(curr_tex_response.x_offset_texture as f64 / curr_tex_response.texture_width as f64, @@ -675,11 +666,9 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { let tex_id2 = gfx.egui_register_texture(curr_tex_response.texture); - let draw_tl_32 = Pos2::new(curr_ui_curs.x as f32, curr_ui_curs.y as f32); - let draw_br_64 = curr_ui_curs_after+nalgebra::Vector2::new(0.0, display_size.y); - let draw_br_32 = Pos2::new(draw_br_64.x as f32, draw_br_64.y as f32); - let r_ret =egui::Rect::from_min_max(draw_tl_32, draw_br_32); - + let draw_tl_32 = Pos2::new(curr_ui_curs.x as f32, curr_ui_curs.y as f32); + let draw_br_32 = Pos2::new((curr_ui_curs.x+display_size.x) as f32, (curr_ui_curs.y+display_size.y) as f32); + let r_ret =egui::Rect::from_min_max(draw_tl_32, draw_br_32); egui::Image::new(tex_id2) .maintain_aspect_ratio(false) @@ -691,148 +680,24 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { ) ) .paint_at(ui, r_ret); - - curr_ui_curs = curr_ui_curs_after; - last_v_size = display_size.y; + //Update display cursor + curr_ui_curs.x += display_size.x; + last_display_size_y = display_size.y; + //Update coordinates for preview rectangle bbox_tl.x = bbox_tl.x.min(r_ret.left()); bbox_tl.y = bbox_tl.y.min(r_ret.top()); - bbox_br.x = bbox_br.x.max(r_ret.right()); bbox_br.y = bbox_br.y.max(r_ret.bottom()); } y_c += y_c_i; - curr_ui_curs += nalgebra::Vector2::new(0.0, last_v_size); + curr_ui_curs.y += last_display_size_y; } let bg_color = Color32::BLACK.linear_multiply(0.5); - - /*let preview_rect = ui - ui.add_space(10.); - let preview_rect = ui - .add( - egui::Image::new(tex_id) - .maintain_aspect_ratio(false) - .fit_to_exact_size(egui::Vec2::splat(desired_width)) - .rounding(ROUNDING) - .uv(egui::Rect::from_x_y_ranges( - uv_center.0 - uv_size.0..=uv_center.0 + uv_size.0, - uv_center.1 - uv_size.1..=uv_center.1 + uv_size.1, - )), - ) - .rect;*/ - - //Pre initialize the rectangle coordinates of the preview window - - - /*//The uv positions in the image, we iterate over - let mut curr_cursor_v = uv_center.1 - uv_size.1; - let end_cursor_u = uv_center.0 + uv_size.0; - let end_cursor_v = uv_center.1 + uv_size.1; - - //Ui position to start at - let base_ui_curs = nalgebra::Vector2::new(ui.cursor().min.x as f64, ui.cursor().min.y as f64); - let mut curr_ui_curs = base_ui_curs; //our start position - - let mut counter_v = 0; //Safety measure... - while curr_cursor_v1.0 && f64::abs(curr_tex.u_tex_right_global-1.0)< f64::EPSILON { - curr_tex_u_end = end_cursor_u; - next_tex_u_begin = end_cursor_u; - } - - if end_cursor_v>1.0 && f64::abs(curr_tex.v_tex_bottom_global-1.0)< f64::EPSILON { - curr_tex_v_end = end_cursor_v; - next_tex_v_begin = end_cursor_v; - } - - //The uv coordinates to draw the picked texture - let u_offset_texture_snipped = curr_tex.u_offset_texture; - let v_offset_texture_snipped = curr_tex.v_offset_texture; - let curr_tex_u_end_texture = (curr_tex_u_end-curr_tex.u_tex_left_global)/curr_tex.u_scale; - let curr_tex_v_end_texture = (curr_tex_v_end-curr_tex.v_tex_top_global)/curr_tex.v_scale; - - //Display size - let u_size = desired_width*(curr_tex_u_end-curr_cursor_u)/(2.0*uv_size.0); - let v_size = desired_width*(curr_tex_v_end-curr_cursor_v)/(2.0*uv_size.1); - - last_v_size = v_size; - let curr_ui_curs_after = curr_ui_curs+nalgebra::Vector2::new(u_size, 0.0); - - //Safety measure: the cursor could perfectly hit the boundary between tiles - if u_size<=f64::EPSILON - { - curr_cursor_u += f64::EPSILON; - continue; - } - - if v_size<=f64::EPSILON - { - curr_cursor_v += f64::EPSILON; - continue; - } - - - let tex_id2 = gfx.egui_register_texture(curr_tex.texture); - let draw_tl_32 = Pos2::new(curr_ui_curs.x as f32, curr_ui_curs.y as f32); - let draw_br_64 = curr_ui_curs_after+nalgebra::Vector2::new(0.0, v_size); - let draw_br_32 = Pos2::new(draw_br_64.x as f32, draw_br_64.y as f32); - let r_ret =egui::Rect::from_min_max(draw_tl_32, draw_br_32); - - egui::Image::new(tex_id2) - .maintain_aspect_ratio(false) - - .fit_to_exact_size(egui::Vec2::new(u_size as f32, v_size as f32)) - .uv(egui::Rect::from_x_y_ranges( - u_offset_texture_snipped as f32 ..=curr_tex_u_end_texture as f32, - v_offset_texture_snipped as f32 ..=curr_tex_v_end_texture as f32, - ) - ) - .paint_at(ui, r_ret); - - - - - //Update coordinates for preview rectangle - bbox_tl.x = bbox_tl.x.min(r_ret.left()); - bbox_tl.y = bbox_tl.y.min(r_ret.top()); - - bbox_br.x = bbox_br.x.max(r_ret.right()); - bbox_br.y = bbox_br.y.max(r_ret.bottom()); - - curr_ui_curs = curr_ui_curs_after; - curr_cursor_u = next_tex_u_begin; - } - - curr_ui_curs += nalgebra::Vector2::new(0.0, last_v_size); - curr_cursor_v = next_tex_v_begin; - }*/ - - - let preview_rect = egui::Rect::from_min_max(bbox_tl, bbox_br); - + let preview_rect = egui::Rect::from_min_max(bbox_tl, bbox_br); ui.advance_cursor_after_rect(preview_rect); From ad91e3eb41be8e36087c40c70326c95415eeb5a2 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 23 Sep 2024 19:37:51 +0200 Subject: [PATCH 22/29] Refactoring pt.4 --- src/texture_wrapper.rs | 133 ++++------------------------------------- src/ui.rs | 33 ++++------ 2 files changed, 21 insertions(+), 145 deletions(-) diff --git a/src/texture_wrapper.rs b/src/texture_wrapper.rs index 5fbfe58f..acf60059 100644 --- a/src/texture_wrapper.rs +++ b/src/texture_wrapper.rs @@ -19,26 +19,9 @@ pub struct TexWrap{ pub size_vec:(f32,f32) // The whole Texture Array size } -pub struct TextureResponse<'a>{ - pub texture: &'a Texture, - pub u_tex_left_global : f64, - pub v_tex_top_global : f64, - pub u_offset_texture : f64, - pub v_offset_texture : f64, - pub u_tex_right_global : f64, - pub v_tex_bottom_global : f64, - pub u_tex_next_right_global : f64, - pub v_tex_next_bottom_global : f64, - pub u_scale:f64, - pub v_scale:f64 -} pub struct TextureResponse2<'a>{ pub texture: &'a Texture, - //pub u_tex_left_global : f64, - //pub v_tex_top_global : f64, - //pub u_tex_right_global : f64, - //pub v_tex_bottom_global : f64, pub x_offset_texture: i32, pub y_offset_texture: i32, @@ -51,18 +34,7 @@ pub struct TextureResponse2<'a>{ pub x_tex_left_global : i32, pub y_tex_top_global : i32, pub x_tex_right_global : i32, - pub y_tex_bottom_global : i32, - - pub x_tex_right_local : i32, - pub y_tex_bottom_local : i32, - - /*pub u_offset_texture : f64, - pub v_offset_texture : f64, - - pub u_tex_next_right_global : f64, - pub v_tex_next_bottom_global : f64, - pub u_scale:f64, - pub v_scale:f64*/ + pub y_tex_bottom_global : i32 } impl TexWrap{ @@ -135,7 +107,7 @@ impl TexWrap{ let im_w = image.width(); let im_h = image.height(); let s = (im_w as f32, im_h as f32); - let max_texture_size = 128;//gfx.limits().max_texture_size; + let max_texture_size = gfx.limits().max_texture_size; let col_count = (im_w as f32/max_texture_size as f32).ceil() as u32; let row_count = (im_h as f32/max_texture_size as f32).ceil() as u32; @@ -183,18 +155,18 @@ impl TexWrap{ } } - pub fn draw_textures(&self,draw: &mut Draw, translation_x:f32, translation_y:f32, scale: f32){ + pub fn draw_textures(&self,draw: &mut Draw, translation_x:f32, translation_y:f32, scale: f32){ let mut tex_idx = 0; for row_idx in 0..self.row_count { - let translate_y = translation_y+scale*row_idx as f32*self.row_translation as f32; + let translate_y = translation_y as f64+scale as f64*row_idx as f64*self.row_translation as f64; for col_idx in 0..self.col_count { - let translate_x = translation_x+scale*col_idx as f32 *self.col_translation as f32; + let translate_x = translation_x as f64+scale as f64*col_idx as f64 *self.col_translation as f64; draw.image(&self.texture_array[tex_idx]) .blend_mode(BlendMode::NORMAL) .scale(scale, scale) - .translate(translate_x.trunc(), translate_y.trunc()); //truncation to avoid artifacts + .translate(translate_x as f32, translate_y as f32); tex_idx += 1; } } @@ -232,13 +204,11 @@ impl TexWrap{ } pub fn get_texture_at_xy(&self, xa:i32, ya:i32)->TextureResponse2{ - - let x = xa.max(0).min(self.width() as i32-1); let y = ya.max(0).min(self.height() as i32-1); - let x_idx = (x /self.col_translation as i32); - let y_idx = (y /self.row_translation as i32); + let x_idx = x /self.col_translation as i32; + let y_idx = y /self.row_translation as i32; let tex_idx = (y_idx*self.col_count as i32+x_idx).min(self.texture_array.len() as i32 -1); let my_tex = &self.texture_array[tex_idx as usize]; @@ -249,11 +219,6 @@ impl TexWrap{ let tex_top = y_idx*self.row_translation as i32; let tex_right = tex_left+width-1; let tex_bottom = tex_top+height-1; - let tex_right_next = tex_right+1; - let tex_bottom_next = tex_bottom+1; - - let u_tex_left_global = tex_left as f64/self.width() as f64; - let v_tex_top_global = tex_top as f64/self.height() as f64; let x_offset_texture = xa-tex_left; let y_offset_texture = ya-tex_top; @@ -261,22 +226,7 @@ impl TexWrap{ let remaining_width = width- x_offset_texture; let remaining_height = height - y_offset_texture; - /*let u_offset = (xa as f64-tex_left as f64)/my_tex.width()as f64; - let v_offset = (ya as f64-tex_top as f64)/my_tex.height()as f64;*/ - - let u_tex_right = tex_right as f64 /self.width()as f64; - let v_tex_bottom = tex_bottom as f64 /self.height()as f64; - - - /*let u_tex_next_right_global = tex_right_next as f64 /self.width()as f64; - let v_tex_next_bottom_global = tex_bottom_next as f64 /self.height()as f64; - - let u_scale = my_tex.width() as f64/self.width() as f64; - let v_scale = my_tex.height() as f64/self.height() as f64;*/ - - TextureResponse2 {texture: my_tex, - //u_tex_left_global, - //v_tex_top_global, + TextureResponse2 {texture: my_tex, x_offset_texture: x_offset_texture, y_offset_texture: y_offset_texture, @@ -288,74 +238,11 @@ impl TexWrap{ x_tex_right_global: tex_right, y_tex_bottom_global: tex_bottom, - x_tex_right_local: self.col_translation as i32-1, - y_tex_bottom_local: self.row_translation as i32-1, offset_width: remaining_width, - offset_height: remaining_height, - - //u_offset_texture:u_offset, - //v_offset_texture:v_offset, - //u_tex_right_global:u_tex_right, - //v_tex_bottom_global:v_tex_bottom, - //u_tex_next_right_global, - //v_tex_next_bottom_global, - //u_scale:u_scale, - //v_scale:v_scale + offset_height: remaining_height } } - pub fn get_texture_at_uv(&self, ua:f64, va:f64)->TextureResponse { - let xa = ua as f64*self.width()as f64; - let ya = va as f64*self.height()as f64; - - let v = (va).max(0.0).min(1.0)as f64; - let u = ua.max(0.0).min(1.0)as f64; - let x = u*self.width()as f64; - let y = v*self.height()as f64; - - let x_idx = (x /self.col_translation as f64).floor() as i32; - let y_idx = (y /self.row_translation as f64).floor() as i32; - let tex_idx = (y_idx*self.col_count as i32+x_idx).min(self.texture_array.len() as i32 -1); - let my_tex = &self.texture_array[tex_idx as usize]; - - let tex_left = x_idx*self.col_translation as i32; - let tex_top = y_idx*self.row_translation as i32; - - //the current texture might be smaller than the set translation. (Last element on x or y axis) - let tex_right_next = tex_left+my_tex.width() as i32; - let tex_bottom_next = tex_top+my_tex.height() as i32; - let tex_right = tex_right_next; - let tex_bottom = tex_bottom_next; - let u_scale = my_tex.width() as f64/self.width() as f64; - let v_scale = my_tex.height() as f64/self.height() as f64; - - - let u_tex_left_global = tex_left as f64/self.width() as f64; - let v_tex_top_global = tex_top as f64/self.height() as f64; - - let u_offset = (xa-tex_left as f64)/my_tex.width()as f64; - let v_offset = (ya-tex_top as f64)/my_tex.height()as f64; - - let u_tex_right = tex_right as f64 /self.width()as f64; - let v_tex_bottom = tex_bottom as f64 /self.height()as f64; - let u_tex_next_right_global = tex_right_next as f64 /self.width()as f64; - let v_tex_next_bottom_global = tex_bottom_next as f64 /self.height()as f64; - - - - TextureResponse {texture: my_tex, - u_tex_left_global, - v_tex_top_global, - u_offset_texture:u_offset, - v_offset_texture:v_offset, - u_tex_right_global:u_tex_right, - v_tex_bottom_global:v_tex_bottom, - u_tex_next_right_global, - v_tex_next_bottom_global, - u_scale:u_scale, - v_scale:v_scale } - } - pub fn size(&self)->(f32,f32){ return self.size_vec; } diff --git a/src/ui.rs b/src/ui.rs index a3a2c79d..d22aa149 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -588,8 +588,6 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { ); ui.end_row(); }); - - // make sure aspect ratio is compensated for the square preview let ratio = texture.size().0 as f64 / texture.size().1 as f64; @@ -598,7 +596,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { (texture.height()as f64*uv_size.1) as i32); let sc1 = (2.0*xy_size.0 as f64 / desired_width, 2.0*xy_size.1 as f64 / desired_width); - println!("image x:{0} y:{1} w:{2} h:{3}", xy_center.0, xy_center.1, xy_size.0, xy_size.1); + //coordinates of the image-view let mut bbox_tl = egui::pos2(f32::MAX, f32::MAX); @@ -613,37 +611,35 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { let mut y_c = xy_center.1-xy_size.1; let y_e = (xy_center.1+xy_size.1) as i32; - while(y_c<=y_e){ + while y_c<=y_e { let mut y_c_i = 0; let mut x_c = xy_center.0-xy_size.0; curr_ui_curs.x = base_ui_curs.x; let mut last_display_size_y: f64 = 0.0; - while(x_c<=x_e){ + while x_c<=x_e { let curr_tex_response = texture.get_texture_at_xy(x_c as i32, y_c as i32); - let x_c_o = x_c; - let y_c_o = y_c; y_c_i = curr_tex_response.offset_height; - print!("xc {0} yc {1} ", x_c, y_c); + x_c += curr_tex_response.offset_width; //Handling last texture in a row or col let mut curr_tex_end = nalgebra::Vector2::new(i32::min(curr_tex_response.x_tex_right_global, x_e), i32::min(curr_tex_response.y_tex_bottom_global, y_e)); - print!("curr_tex_x_end {0} curr_tex_y_end {1} ", curr_tex_end.x, curr_tex_end.y); + //Handling positive overflow - if(curr_tex_response.x_tex_right_global as f32>= texture.width()-1.0f32){ + if curr_tex_response.x_tex_right_global as f32>= texture.width()-1.0f32 { x_c = x_e+1; curr_tex_end.x += (x_e-curr_tex_response.x_tex_right_global).max(0); } - if(curr_tex_response.y_tex_bottom_global as f32>= texture.height()-1.0f32){ + if curr_tex_response.y_tex_bottom_global as f32>= texture.height()-1.0f32 { y_c_i = y_e-y_c+1; curr_tex_end.y += (y_e-curr_tex_response.y_tex_bottom_global).max(0); } - println!("curr_tex_x_end {0} curr_tex_y_end {1} ", curr_tex_end.x, curr_tex_end.y); + //End of texture, display width let tile_size = nalgebra::Vector2::new(curr_tex_end.x-curr_tex_response.x_offset_texture-curr_tex_response.x_tex_left_global+1, @@ -657,12 +653,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { curr_tex_response.y_offset_texture as f64 / curr_tex_response.texture_height as f64); let uv_end = nalgebra::Vector2::new((curr_tex_end.x-curr_tex_response.x_tex_left_global+1) as f64 / curr_tex_response.texture_width as f64, - (curr_tex_end.y-curr_tex_response.y_tex_top_global+1) as f64 / curr_tex_response.texture_height as f64); - - println!("Using Texture x_c {0} y_c {1} {2} {3} xe {4} ye {5} tex bo {6} wx {7} wy {8} u-b{9} v-b{10} u-e{11} v-b{12} y_c after {13}]", - x_c_o, y_c_o, curr_tex_end.x, curr_tex_end.y, x_e, y_e, curr_tex_response.y_tex_bottom_global, - tile_size.x, tile_size.y, uv_start.x, uv_start.y, uv_end.x, - uv_end.y, y_c_o+y_c_i); + (curr_tex_end.y-curr_tex_response.y_tex_top_global+1) as f64 / curr_tex_response.texture_height as f64); let tex_id2 = gfx.egui_register_texture(curr_tex_response.texture); @@ -671,13 +662,11 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { let r_ret =egui::Rect::from_min_max(draw_tl_32, draw_br_32); egui::Image::new(tex_id2) - .maintain_aspect_ratio(false) - + .maintain_aspect_ratio(false) .fit_to_exact_size(egui::Vec2::new(display_size.x as f32, display_size.y as f32)) .uv(egui::Rect::from_x_y_ranges( uv_start.x as f32 ..=uv_end.x as f32, - uv_start.y as f32 ..=uv_end.y as f32, - ) + uv_start.y as f32 ..=uv_end.y as f32) ) .paint_at(ui, r_ret); From 3c2faa6bb4fba5879fcb5cb8dc3fc21ea2955b96 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 23 Sep 2024 21:46:40 +0200 Subject: [PATCH 23/29] Refactoring pt.5 --- src/ui.rs | 52 +++++++++++++++++++++++++--------------------------- src/utils.rs | 24 ++++++++++++------------ 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/src/ui.rs b/src/ui.rs index 533a7a62..c2412863 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -606,46 +606,43 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { let base_ui_curs = nalgebra::Vector2::new(ui.cursor().min.x as f64, ui.cursor().min.y as f64); let mut curr_ui_curs = base_ui_curs; //our start position - //Loop control variables - let x_e = (xy_center.0+xy_size.0) as i32; - let mut y_c = xy_center.1-xy_size.1; - let y_e = (xy_center.1+xy_size.1) as i32; - - while y_c<=y_e { - let mut y_c_i = 0; - let mut x_c = xy_center.0-xy_size.0; + //Loop control variables, start end end coordinates of interest + let x_coordinate_end = (xy_center.0+xy_size.0) as i32; + let mut y_coordinate = xy_center.1-xy_size.1; + let y_coordinate_end = (xy_center.1+xy_size.1) as i32; + + while y_coordinate<=y_coordinate_end { + let mut y_coordinate_increment = 0; //increment for y coordinate after x loop + let mut x_coordinate = xy_center.0-xy_size.0; curr_ui_curs.x = base_ui_curs.x; let mut last_display_size_y: f64 = 0.0; - while x_c<=x_e { - let curr_tex_response = texture.get_texture_at_xy(x_c as i32, y_c as i32); - - y_c_i = curr_tex_response.offset_height; - + while x_coordinate<=x_coordinate_end { + //get texture tile + let curr_tex_response = texture.get_texture_at_xy(x_coordinate as i32, y_coordinate as i32); - x_c += curr_tex_response.offset_width; + //increment coordinates by usable width/height + y_coordinate_increment = curr_tex_response.offset_height; + x_coordinate += curr_tex_response.offset_width; //Handling last texture in a row or col - let mut curr_tex_end = nalgebra::Vector2::new(i32::min(curr_tex_response.x_tex_right_global, x_e), i32::min(curr_tex_response.y_tex_bottom_global, y_e)); - - + let mut curr_tex_end = nalgebra::Vector2::new(i32::min(curr_tex_response.x_tex_right_global, x_coordinate_end), i32::min(curr_tex_response.y_tex_bottom_global, y_coordinate_end)); - //Handling positive overflow + //Handling positive coordinate overflow if curr_tex_response.x_tex_right_global as f32>= texture.width()-1.0f32 { - x_c = x_e+1; - curr_tex_end.x += (x_e-curr_tex_response.x_tex_right_global).max(0); + x_coordinate = x_coordinate_end+1; + curr_tex_end.x += (x_coordinate_end-curr_tex_response.x_tex_right_global).max(0); } if curr_tex_response.y_tex_bottom_global as f32>= texture.height()-1.0f32 { - y_c_i = y_e-y_c+1; - curr_tex_end.y += (y_e-curr_tex_response.y_tex_bottom_global).max(0); - } - + y_coordinate_increment = y_coordinate_end-y_coordinate+1; + curr_tex_end.y += (y_coordinate_end-curr_tex_response.y_tex_bottom_global).max(0); + } - //End of texture, display width + //Usable tile size, depending on offsets let tile_size = nalgebra::Vector2::new(curr_tex_end.x-curr_tex_response.x_offset_texture-curr_tex_response.x_tex_left_global+1, curr_tex_end.y-curr_tex_response.y_offset_texture-curr_tex_response.y_tex_top_global+1); - //Display size + //Display size - tile size scaled let display_size = nalgebra::Vector2::new(tile_size.x as f64/sc1.0,tile_size.y as f64/sc1.1); //Texture display range @@ -681,7 +678,8 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { bbox_br.y = bbox_br.y.max(r_ret.bottom()); } - y_c += y_c_i; + //Update y coordinates + y_coordinate += y_coordinate_increment; curr_ui_curs.y += last_display_size_y; } diff --git a/src/utils.rs b/src/utils.rs index 942306be..1181ad54 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -87,9 +87,9 @@ pub struct ExtendedImageInfo { pub num_pixels: usize, pub num_transparent_pixels: usize, pub num_colors: usize, - pub red_histogram: Vec<(i32, i32)>, - pub green_histogram: Vec<(i32, i32)>, - pub blue_histogram: Vec<(i32, i32)>, + pub red_histogram: Vec<(i32, u64)>, + pub green_histogram: Vec<(i32, u64)>, + pub blue_histogram: Vec<(i32, u64)>, pub exif: HashMap, pub raw_exif: Option, pub name: String, @@ -155,9 +155,9 @@ impl ExtendedImageInfo { pub fn from_image(img: &RgbaImage) -> Self { - let mut hist_r: [u32; 256] = [0; 256]; - let mut hist_g: [u32; 256] = [0; 256]; - let mut hist_b: [u32; 256] = [0; 256]; + let mut hist_r: [u64; 256] = [0; 256]; + let mut hist_g: [u64; 256] = [0; 256]; + let mut hist_b: [u64; 256] = [0; 256]; let num_pixels = img.width() as usize * img.height() as usize; let mut num_transparent_pixels = 0; @@ -192,22 +192,22 @@ impl ExtendedImageInfo { } - let green_histogram: Vec<(i32, i32)> = hist_g + let green_histogram: Vec<(i32, u64)> = hist_g .iter() .enumerate() - .map(|(k, v)| (k as i32, *v as i32)) + .map(|(k, v)| (k as i32, *v)) .collect(); - let red_histogram: Vec<(i32, i32)> = hist_r + let red_histogram: Vec<(i32, u64)> = hist_r .iter() .enumerate() - .map(|(k, v)| (k as i32, *v as i32)) + .map(|(k, v)| (k as i32, *v)) .collect(); - let blue_histogram: Vec<(i32, i32)> = hist_b + let blue_histogram: Vec<(i32, u64)> = hist_b .iter() .enumerate() - .map(|(k, v)| (k as i32, *v as i32)) + .map(|(k, v)| (k as i32, *v)) .collect(); Self { From 3fab4f9a82ece789c3eafc13ca15a584350ea9ac Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 23 Sep 2024 21:51:53 +0200 Subject: [PATCH 24/29] Refactoring pt.6 --- src/texture_wrapper.rs | 11 ++--------- src/utils.rs | 2 +- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/texture_wrapper.rs b/src/texture_wrapper.rs index acf60059..8a24fb2e 100644 --- a/src/texture_wrapper.rs +++ b/src/texture_wrapper.rs @@ -38,13 +38,6 @@ pub struct TextureResponse2<'a>{ } impl TexWrap{ - /*pub fn new(texture: Texture) -> Self{ - let s = texture.size(); - TexWrap { tex: texture, size_vec:s } - }*/ - - //pub fn from_rgba_image_premult(gfx: &mut Graphics, linear_mag_filter: bool, image: &RgbaImage) -> Option{} - pub fn from_rgbaimage(gfx: &mut Graphics, settings: &PersistentSettings, image: &RgbaImage) -> Option{ Self::gen_from_rgbaimage(gfx, settings, image, Self::gen_texture_standard) } @@ -102,7 +95,7 @@ impl TexWrap{ .ok() } - fn gen_from_rgbaimage(gfx: &mut Graphics, settings: &PersistentSettings, image: &RgbaImage, fuuun: fn (&mut Graphics, &[u8], u32, u32, &PersistentSettings)-> Option) -> Option{ + fn gen_from_rgbaimage(gfx: &mut Graphics, settings: &PersistentSettings, image: &RgbaImage, texture_generator_function: fn (&mut Graphics, &[u8], u32, u32, &PersistentSettings)-> Option) -> Option{ let im_w = image.width(); let im_h = image.height(); @@ -131,7 +124,7 @@ impl TexWrap{ let sub_img = imageops::crop_imm(image, tex_start_x, tex_start_y, tex_width, tex_height); let my_img = sub_img.to_image(); - let tex = fuuun(gfx, my_img.as_ref(), my_img.width(), my_img.height(), settings); + let tex = texture_generator_function(gfx, my_img.as_ref(), my_img.width(), my_img.height(), settings); if let Some(t) = tex { a.push(t); diff --git a/src/utils.rs b/src/utils.rs index 1181ad54..0b75dcf4 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -336,7 +336,7 @@ pub fn send_image_threaded( // .send(Frame::new_reset(f.buffer.clone())); let mut first = true; - for mut f in frame_receiver.iter() { + for f in frame_receiver.iter() { if stop_receiver.try_recv().is_ok() { debug!("Stopped from receiver."); return; From bd957c032cb2283d6dce99ba126f0702b2c49f5d Mon Sep 17 00:00:00 2001 From: Simon Date: Sat, 28 Sep 2024 20:54:29 +0200 Subject: [PATCH 25/29] Refactoring of tiled info image rendering, automatic disabling of mipmaps to save memory --- src/texture_wrapper.rs | 37 ++++--- src/ui.rs | 212 +++++++++++++++++++++++------------------ src/utils.rs | 8 +- 3 files changed, 146 insertions(+), 111 deletions(-) diff --git a/src/texture_wrapper.rs b/src/texture_wrapper.rs index 8a24fb2e..15645d68 100644 --- a/src/texture_wrapper.rs +++ b/src/texture_wrapper.rs @@ -1,3 +1,4 @@ +use log::warn; use notan::draw::*; use crate::Draw; @@ -16,7 +17,8 @@ pub struct TexWrap{ pub row_count:u32, pub col_translation:u32, pub row_translation:u32, - pub size_vec:(f32,f32) // The whole Texture Array size + pub size_vec:(f32,f32), // The whole Texture Array size + pub texture_count:usize } @@ -46,11 +48,11 @@ impl TexWrap{ Self::gen_from_rgbaimage(gfx, settings, image, Self::gen_texture_premult) } - fn gen_texture_standard(gfx: &mut Graphics, bytes:&[u8], width:u32, height:u32, settings: &PersistentSettings)-> Option + fn gen_texture_standard(gfx: &mut Graphics, bytes:&[u8], width:u32, height:u32, settings: &PersistentSettings, size_ok: bool)-> Option { gfx.create_texture() .from_bytes(bytes, width, height) - .with_mipmaps(settings.use_mipmaps) + .with_mipmaps(settings.use_mipmaps&&size_ok) // .with_format(notan::prelude::TextureFormat::SRgba8) // .with_premultiplied_alpha() .with_filter( @@ -70,12 +72,12 @@ impl TexWrap{ .ok() } - fn gen_texture_premult(gfx: &mut Graphics, bytes:&[u8], width:u32, height:u32, settings: &PersistentSettings)-> Option + fn gen_texture_premult(gfx: &mut Graphics, bytes:&[u8], width:u32, height:u32, settings: &PersistentSettings, size_ok: bool)-> Option { gfx.create_texture() .from_bytes(bytes, width, height) .with_premultiplied_alpha() - .with_mipmaps(settings.use_mipmaps) + .with_mipmaps(settings.use_mipmaps&&size_ok) // .with_format(notan::prelude::TextureFormat::SRgba8) // .with_premultiplied_alpha() .with_filter( @@ -95,16 +97,24 @@ impl TexWrap{ .ok() } - fn gen_from_rgbaimage(gfx: &mut Graphics, settings: &PersistentSettings, image: &RgbaImage, texture_generator_function: fn (&mut Graphics, &[u8], u32, u32, &PersistentSettings)-> Option) -> Option{ - + fn gen_from_rgbaimage(gfx: &mut Graphics, settings: &PersistentSettings, image: &RgbaImage, texture_generator_function: fn (&mut Graphics, &[u8], u32, u32, &PersistentSettings, bool)-> Option) -> Option{ + const MAX_PIXEL_COUNT:usize = 8192*8192; + let im_w = image.width(); let im_h = image.height(); + let im_sz = (im_w*im_h) as usize; + let allow_mipmap = im_sz < MAX_PIXEL_COUNT; + + if !allow_mipmap { + warn!("Image with {0} pixels too large (max {1} pixels), disabling mipmaps", im_sz, MAX_PIXEL_COUNT); + } + let s = (im_w as f32, im_h as f32); let max_texture_size = gfx.limits().max_texture_size; let col_count = (im_w as f32/max_texture_size as f32).ceil() as u32; let row_count = (im_h as f32/max_texture_size as f32).ceil() as u32; - let mut a:Vec = Vec::new(); + let mut texture_vec:Vec = Vec::new(); let row_increment = std::cmp::min(max_texture_size, im_h); let col_increment = std::cmp::min(max_texture_size, im_w); let mut fine = true; @@ -124,13 +134,13 @@ impl TexWrap{ let sub_img = imageops::crop_imm(image, tex_start_x, tex_start_y, tex_width, tex_height); let my_img = sub_img.to_image(); - let tex = texture_generator_function(gfx, my_img.as_ref(), my_img.width(), my_img.height(), settings); + let tex = texture_generator_function(gfx, my_img.as_ref(), my_img.width(), my_img.height(), settings, allow_mipmap); if let Some(t) = tex { - a.push(t); + texture_vec.push(t); } else{ - a.clear(); + texture_vec.clear(); fine = false; break; } @@ -141,7 +151,8 @@ impl TexWrap{ } if fine { - Some(TexWrap {size_vec:s, col_count:col_count, row_count:row_count,texture_array:a, col_translation:col_increment, row_translation:row_increment }) + let texture_count = texture_vec.len(); + Some(TexWrap {size_vec:s, col_count:col_count, row_count:row_count,texture_array:texture_vec, col_translation:col_increment, row_translation:row_increment, texture_count}) } else { None @@ -165,7 +176,7 @@ impl TexWrap{ } } - pub fn update_textures(&mut self, gfx: &mut Graphics, image: &RgbaImage){ + pub fn update_textures(&mut self, gfx: &mut Graphics, image: &RgbaImage){ if self.col_count==1 && self.row_count==1 { if let Err(e) = gfx.update_texture(&mut self.texture_array[0]).with_data(image).update() { error!("{e}"); diff --git a/src/ui.rs b/src/ui.rs index c2412863..b5ffce04 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -531,10 +531,6 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { (state.cursor_relative.y as f64 / state.image_geometry.dimensions.1 as f64), ); - let xy_center = ((texture.width() as f64*uv_center.0) as i32, (texture.height() as f64*uv_center.1) as i32); //(16384,1024);// - - - egui::Grid::new("info") .num_columns(2) .show(ui, |ui| { @@ -591,96 +587,30 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { // make sure aspect ratio is compensated for the square preview let ratio = texture.size().0 as f64 / texture.size().1 as f64; - let uv_size = (scale, scale * ratio); - let xy_size = ((texture.width()as f64*uv_size.0) as i32, - (texture.height()as f64*uv_size.1) as i32); - let sc1 = (2.0*xy_size.0 as f64 / desired_width, - 2.0*xy_size.1 as f64 / desired_width); - - - //coordinates of the image-view - let mut bbox_tl = egui::pos2(f32::MAX, f32::MAX); - let mut bbox_br = egui::pos2(f32::MIN, f32::MIN); - - //Ui position to start at - let base_ui_curs = nalgebra::Vector2::new(ui.cursor().min.x as f64, ui.cursor().min.y as f64); - let mut curr_ui_curs = base_ui_curs; //our start position - - //Loop control variables, start end end coordinates of interest - let x_coordinate_end = (xy_center.0+xy_size.0) as i32; - let mut y_coordinate = xy_center.1-xy_size.1; - let y_coordinate_end = (xy_center.1+xy_size.1) as i32; - - while y_coordinate<=y_coordinate_end { - let mut y_coordinate_increment = 0; //increment for y coordinate after x loop - let mut x_coordinate = xy_center.0-xy_size.0; - curr_ui_curs.x = base_ui_curs.x; - let mut last_display_size_y: f64 = 0.0; - while x_coordinate<=x_coordinate_end { - //get texture tile - let curr_tex_response = texture.get_texture_at_xy(x_coordinate as i32, y_coordinate as i32); - - //increment coordinates by usable width/height - y_coordinate_increment = curr_tex_response.offset_height; - x_coordinate += curr_tex_response.offset_width; - - //Handling last texture in a row or col - let mut curr_tex_end = nalgebra::Vector2::new(i32::min(curr_tex_response.x_tex_right_global, x_coordinate_end), i32::min(curr_tex_response.y_tex_bottom_global, y_coordinate_end)); - - //Handling positive coordinate overflow - if curr_tex_response.x_tex_right_global as f32>= texture.width()-1.0f32 { - x_coordinate = x_coordinate_end+1; - curr_tex_end.x += (x_coordinate_end-curr_tex_response.x_tex_right_global).max(0); - } - - if curr_tex_response.y_tex_bottom_global as f32>= texture.height()-1.0f32 { - y_coordinate_increment = y_coordinate_end-y_coordinate+1; - curr_tex_end.y += (y_coordinate_end-curr_tex_response.y_tex_bottom_global).max(0); - } - - //Usable tile size, depending on offsets - let tile_size = nalgebra::Vector2::new(curr_tex_end.x-curr_tex_response.x_offset_texture-curr_tex_response.x_tex_left_global+1, - curr_tex_end.y-curr_tex_response.y_offset_texture-curr_tex_response.y_tex_top_global+1); - - //Display size - tile size scaled - let display_size = nalgebra::Vector2::new(tile_size.x as f64/sc1.0,tile_size.y as f64/sc1.1); - - //Texture display range - let uv_start = nalgebra::Vector2::new(curr_tex_response.x_offset_texture as f64 / curr_tex_response.texture_width as f64, - curr_tex_response.y_offset_texture as f64 / curr_tex_response.texture_height as f64); - - let uv_end = nalgebra::Vector2::new((curr_tex_end.x-curr_tex_response.x_tex_left_global+1) as f64 / curr_tex_response.texture_width as f64, - (curr_tex_end.y-curr_tex_response.y_tex_top_global+1) as f64 / curr_tex_response.texture_height as f64); - - - let tex_id2 = gfx.egui_register_texture(curr_tex_response.texture); - let draw_tl_32 = Pos2::new(curr_ui_curs.x as f32, curr_ui_curs.y as f32); - let draw_br_32 = Pos2::new((curr_ui_curs.x+display_size.x) as f32, (curr_ui_curs.y+display_size.y) as f32); - let r_ret =egui::Rect::from_min_max(draw_tl_32, draw_br_32); - - egui::Image::new(tex_id2) - .maintain_aspect_ratio(false) - .fit_to_exact_size(egui::Vec2::new(display_size.x as f32, display_size.y as f32)) - .uv(egui::Rect::from_x_y_ranges( - uv_start.x as f32 ..=uv_end.x as f32, - uv_start.y as f32 ..=uv_end.y as f32) + let uv_size = (scale, scale * ratio); + let bbox_tl: Pos2; + let bbox_br: Pos2; + if texture.texture_count==1 { + let texture_resonse = texture.get_texture_at_xy(0,0); + let tex_id = gfx.egui_register_texture(texture_resonse.texture); + ui.add_space(10.); + let preview_rect = ui + .add( + egui::Image::new(tex_id) + .maintain_aspect_ratio(false) + .fit_to_exact_size(egui::Vec2::splat(desired_width as f32)) + .rounding(ROUNDING) + .uv(egui::Rect::from_x_y_ranges( + (uv_center.0 - uv_size.0) as f32..=(uv_center.0 + uv_size.0) as f32, + (uv_center.1 - uv_size.1) as f32..=(uv_center.1 + uv_size.1) as f32, + )), ) - .paint_at(ui, r_ret); - - //Update display cursor - curr_ui_curs.x += display_size.x; - last_display_size_y = display_size.y; - - //Update coordinates for preview rectangle - bbox_tl.x = bbox_tl.x.min(r_ret.left()); - bbox_tl.y = bbox_tl.y.min(r_ret.top()); - bbox_br.x = bbox_br.x.max(r_ret.right()); - bbox_br.y = bbox_br.y.max(r_ret.bottom()); - - } - //Update y coordinates - y_coordinate += y_coordinate_increment; - curr_ui_curs.y += last_display_size_y; + .rect; + bbox_tl = preview_rect.left_top(); + bbox_br = preview_rect.right_bottom(); + } + else{ + (bbox_tl, bbox_br) = render_info_image_tiled(ui, uv_center,uv_size, desired_width, texture, gfx); } let bg_color = Color32::BLACK.linear_multiply(0.5); @@ -833,6 +763,102 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { }); } +fn render_info_image_tiled(ui: &mut Ui, uv_center: (f64, f64), uv_size: (f64, f64), desired_width: f64, texture: &crate::texture_wrapper::TexWrap, gfx: &mut Graphics) -> (Pos2, Pos2) { + let xy_size = ((texture.width()as f64*uv_size.0) as i32, + (texture.height()as f64*uv_size.1) as i32); + + let xy_center = ((texture.width() as f64*uv_center.0) as i32, (texture.height() as f64*uv_center.1) as i32); //(16384,1024);// + let sc1 = (2.0*xy_size.0 as f64 / desired_width, + 2.0*xy_size.1 as f64 / desired_width); + + //coordinates of the image-view + let mut bbox_tl = egui::pos2(f32::MAX, f32::MAX); + let mut bbox_br = egui::pos2(f32::MIN, f32::MIN); + + //Ui position to start at + let base_ui_curs = nalgebra::Vector2::new(ui.cursor().min.x as f64, ui.cursor().min.y as f64); + let mut curr_ui_curs = base_ui_curs; + //our start position + + //Loop control variables, start end end coordinates of interest + let x_coordinate_end = (xy_center.0+xy_size.0) as i32; + let mut y_coordinate = xy_center.1-xy_size.1; + let y_coordinate_end = (xy_center.1+xy_size.1) as i32; + + while y_coordinate<=y_coordinate_end { + let mut y_coordinate_increment = 0; //increment for y coordinate after x loop + let mut x_coordinate = xy_center.0-xy_size.0; + curr_ui_curs.x = base_ui_curs.x; + let mut last_display_size_y: f64 = 0.0; + while x_coordinate<=x_coordinate_end { + //get texture tile + let curr_tex_response = texture.get_texture_at_xy(x_coordinate as i32, y_coordinate as i32); + + //increment coordinates by usable width/height + y_coordinate_increment = curr_tex_response.offset_height; + x_coordinate += curr_tex_response.offset_width; + + //Handling last texture in a row or col + let mut curr_tex_end = nalgebra::Vector2::new(i32::min(curr_tex_response.x_tex_right_global, x_coordinate_end), i32::min(curr_tex_response.y_tex_bottom_global, y_coordinate_end)); + + //Handling positive coordinate overflow + if curr_tex_response.x_tex_right_global as f32>= texture.width()-1.0f32 { + x_coordinate = x_coordinate_end+1; + curr_tex_end.x += (x_coordinate_end-curr_tex_response.x_tex_right_global).max(0); + } + + if curr_tex_response.y_tex_bottom_global as f32>= texture.height()-1.0f32 { + y_coordinate_increment = y_coordinate_end-y_coordinate+1; + curr_tex_end.y += (y_coordinate_end-curr_tex_response.y_tex_bottom_global).max(0); + } + + //Usable tile size, depending on offsets + let tile_size = nalgebra::Vector2::new(curr_tex_end.x-curr_tex_response.x_offset_texture-curr_tex_response.x_tex_left_global+1, + curr_tex_end.y-curr_tex_response.y_offset_texture-curr_tex_response.y_tex_top_global+1); + + //Display size - tile size scaled + let display_size = nalgebra::Vector2::new(tile_size.x as f64/sc1.0,tile_size.y as f64/sc1.1); + + //Texture display range + let uv_start = nalgebra::Vector2::new(curr_tex_response.x_offset_texture as f64 / curr_tex_response.texture_width as f64, + curr_tex_response.y_offset_texture as f64 / curr_tex_response.texture_height as f64); + + let uv_end = nalgebra::Vector2::new((curr_tex_end.x-curr_tex_response.x_tex_left_global+1) as f64 / curr_tex_response.texture_width as f64, + (curr_tex_end.y-curr_tex_response.y_tex_top_global+1) as f64 / curr_tex_response.texture_height as f64); + + + let tex_id2 = gfx.egui_register_texture(curr_tex_response.texture); + let draw_tl_32 = Pos2::new(curr_ui_curs.x as f32, curr_ui_curs.y as f32); + let draw_br_32 = Pos2::new((curr_ui_curs.x+display_size.x) as f32, (curr_ui_curs.y+display_size.y) as f32); + let r_ret =egui::Rect::from_min_max(draw_tl_32, draw_br_32); + + egui::Image::new(tex_id2) + .maintain_aspect_ratio(false) + .fit_to_exact_size(egui::Vec2::new(display_size.x as f32, display_size.y as f32)) + .uv(egui::Rect::from_x_y_ranges( + uv_start.x as f32 ..=uv_end.x as f32, + uv_start.y as f32 ..=uv_end.y as f32) + ) + .paint_at(ui, r_ret); + + //Update display cursor + curr_ui_curs.x += display_size.x; + last_display_size_y = display_size.y; + + //Update coordinates for preview rectangle + bbox_tl.x = bbox_tl.x.min(r_ret.left()); + bbox_tl.y = bbox_tl.y.min(r_ret.top()); + bbox_br.x = bbox_br.x.max(r_ret.right()); + bbox_br.y = bbox_br.y.max(r_ret.bottom()); + + } + //Update y coordinates + y_coordinate += y_coordinate_increment; + curr_ui_curs.y += last_display_size_y; + } + (bbox_tl, bbox_br) +} + pub fn settings_ui(app: &mut App, ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { let mut settings_enabled = state.settings_enabled; egui::Window::new("Preferences") diff --git a/src/utils.rs b/src/utils.rs index 0b75dcf4..9ffe937a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -294,8 +294,7 @@ impl Player { img_location, self.image_sender.clone(), message_sender, - stop_receiver, - forced_frame_source, + stop_receiver ); if let Ok(meta) = std::fs::metadata(img_location) { @@ -318,8 +317,7 @@ pub fn send_image_threaded( img_location: &Path, texture_sender: Sender, message_sender: Sender, - stop_receiver: Receiver<()>, - forced_frame_source: Option, + stop_receiver: Receiver<()> ) { let loc = img_location.to_owned(); @@ -340,7 +338,7 @@ pub fn send_image_threaded( if stop_receiver.try_recv().is_ok() { debug!("Stopped from receiver."); return; - } + } // a "normal image (no animation)" if f.source == FrameSource::Still { debug!("Received image in {:?}", timer.elapsed()); From 7f6d863d54e9871d7d96c1f87c395025e50813c9 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 29 Sep 2024 08:30:24 +0200 Subject: [PATCH 26/29] Refactoring pt.6 --- src/texture_wrapper.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/texture_wrapper.rs b/src/texture_wrapper.rs index 15645d68..ad8d4606 100644 --- a/src/texture_wrapper.rs +++ b/src/texture_wrapper.rs @@ -102,14 +102,14 @@ impl TexWrap{ let im_w = image.width(); let im_h = image.height(); - let im_sz = (im_w*im_h) as usize; - let allow_mipmap = im_sz < MAX_PIXEL_COUNT; + let im_pixel_count = (im_w*im_h) as usize; + let allow_mipmap = im_pixel_count < MAX_PIXEL_COUNT; if !allow_mipmap { - warn!("Image with {0} pixels too large (max {1} pixels), disabling mipmaps", im_sz, MAX_PIXEL_COUNT); + warn!("Image with {0} pixels too large (max {1} pixels), disabling mipmaps", im_pixel_count, MAX_PIXEL_COUNT); } - let s = (im_w as f32, im_h as f32); + let im_size = (im_w as f32, im_h as f32); let max_texture_size = gfx.limits().max_texture_size; let col_count = (im_w as f32/max_texture_size as f32).ceil() as u32; let row_count = (im_h as f32/max_texture_size as f32).ceil() as u32; @@ -139,20 +139,20 @@ impl TexWrap{ if let Some(t) = tex { texture_vec.push(t); } - else{ + else{ //On error texture_vec.clear(); fine = false; break; } } - if fine == false { + if !fine{//early exit if we failed break; } } if fine { let texture_count = texture_vec.len(); - Some(TexWrap {size_vec:s, col_count:col_count, row_count:row_count,texture_array:texture_vec, col_translation:col_increment, row_translation:row_increment, texture_count}) + Some(TexWrap {size_vec:im_size, col_count:col_count, row_count:row_count,texture_array:texture_vec, col_translation:col_increment, row_translation:row_increment, texture_count}) } else { None From 60e3f4c1eab427a9107788cb26b1edf46e686a8c Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 6 Oct 2024 18:34:18 +0200 Subject: [PATCH 27/29] Unregistering egui textures when a new texture is created. --- src/appstate.rs | 17 +++++----- src/main.rs | 26 ++++++++-------- src/texture_wrapper.rs | 71 ++++++++++++++++++++++++++++++++++-------- src/ui.rs | 62 +++++++++++++++++------------------- src/utils.rs | 2 +- 5 files changed, 108 insertions(+), 70 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index 7c11dfec..8d0e2c5e 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -1,9 +1,5 @@ use crate::{ - image_editing::EditState, - scrubber::Scrubber, - settings::{PersistentSettings, VolatileSettings}, - utils::{ExtendedImageInfo, Frame, Player}, - texture_wrapper::TexWrap + image_editing::EditState, scrubber::Scrubber, settings::{PersistentSettings, VolatileSettings}, texture_wrapper::TextureWrapperManager, utils::{ExtendedImageInfo, Frame, Player} }; use egui_notify::Toasts; @@ -49,7 +45,7 @@ impl Message { /// The state of the application #[derive(AppState)] -pub struct OculanteState { +pub struct OculanteState{ pub image_geometry: ImageGeometry, pub compare_list: HashMap, pub drag_enabled: bool, @@ -69,7 +65,8 @@ pub struct OculanteState { pub extended_info_loading: bool, /// The Player, responsible for loading and sending Frames pub player: Player, - pub current_texture: Option, + //pub current_texture: Option, + pub current_texture: TextureWrapperManager, pub current_path: Option, pub current_image: Option, pub settings_enabled: bool, @@ -96,7 +93,7 @@ pub struct OculanteState { pub filebrowser_id: Option, } -impl OculanteState { +impl<'b> OculanteState{ pub fn send_message_info(&self, msg: &str) { _ = self.message_channel.0.send(Message::info(msg)); } @@ -110,8 +107,8 @@ impl OculanteState { } } -impl Default for OculanteState { - fn default() -> OculanteState { +impl<'b> Default for OculanteState{ + fn default() -> OculanteState{ let tx_channel = mpsc::channel(); OculanteState { image_geometry: ImageGeometry { diff --git a/src/main.rs b/src/main.rs index b8e1ab2e..c03f51c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -678,7 +678,7 @@ fn update(app: &mut App, state: &mut OculanteState) { if state.first_start { app.window().set_always_on_top(false); } - + if let Some(p) = &state.current_path { let t = app.timer.elapsed_f32() % 0.8; if t <= 0.05 { @@ -759,7 +759,7 @@ fn update(app: &mut App, state: &mut OculanteState) { state.toasts.error(e); state.current_image = None; state.is_loaded = true; - state.current_texture = None; + state.current_texture.clear(); } Message::Info(m) => { state @@ -866,7 +866,7 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O } } // always reset if first image - if state.current_texture.is_none() { + if state.current_texture.get().is_none() { state.reset_image = true; } @@ -923,7 +923,7 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O debug!("Received compare result"); // always reset if first image - if state.current_texture.is_none() { + if state.current_texture.get().is_none() { state.reset_image = true; } @@ -931,29 +931,29 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O } } - if let Some(tex) = &mut state.current_texture { + if let Some(tex) = &mut state.current_texture.get() { if tex.width() as u32 == img.width() && tex.height() as u32 == img.height() { img.update_texture_with_texwrap(gfx, tex); - } else { - state.current_texture = img.to_texture(gfx, &state.persistent_settings); + } else { + state.current_texture.set(img.to_texture(gfx, &state.persistent_settings), gfx); } } else { debug!("Setting texture"); - state.current_texture = img.to_texture(gfx, &state.persistent_settings); + state.current_texture.set(img.to_texture(gfx, &state.persistent_settings), gfx); } match &state.persistent_settings.current_channel { // Unpremultiply the image ColorChannel::Rgb => { - state.current_texture = unpremult(&img).to_texture(gfx, &state.persistent_settings) + state.current_texture.set(unpremult(&img).to_texture(gfx, &state.persistent_settings), gfx) } // Do nuttin' ColorChannel::Rgba => (), // Display the channel _ => { - state.current_texture = - solo_channel(&img, state.persistent_settings.current_channel as usize) - .to_texture(gfx, &state.persistent_settings) + + state.current_texture.set(solo_channel(&img, state.persistent_settings.current_channel as usize) + .to_texture(gfx, &state.persistent_settings),gfx); } } state.current_image = Some(img); @@ -1097,7 +1097,7 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O settings_ui(app, ctx, state, gfx); }); - if let Some(texture) = &state.current_texture { + if let Some(texture) = &state.current_texture.get() { // align to pixel to prevent distortion let aligned_offset_x = state.image_geometry.offset.x.trunc(); let aligned_offset_y = state.image_geometry.offset.y.trunc(); diff --git a/src/texture_wrapper.rs b/src/texture_wrapper.rs index ad8d4606..7ca30298 100644 --- a/src/texture_wrapper.rs +++ b/src/texture_wrapper.rs @@ -1,5 +1,7 @@ use log::warn; use notan::draw::*; +use notan::egui::EguiRegisterTexture; +use notan::egui::SizedTexture; use crate::Draw; use crate::settings::PersistentSettings; @@ -12,7 +14,7 @@ use notan::prelude::{Graphics, Texture, TextureFilter, BlendMode}; use log::error; pub struct TexWrap{ - texture_array:Vec, + texture_array:Vec, pub col_count:u32, pub row_count:u32, pub col_translation:u32, @@ -21,9 +23,36 @@ pub struct TexWrap{ pub texture_count:usize } +#[derive(Default)] +pub struct TextureWrapperManager{ + current_texture: Option +} + +impl TextureWrapperManager{ + + pub fn set(&mut self, tex: Option,gfx: &mut Graphics){ + if let Some(texture) = &mut self.current_texture { + texture.unregister_textures(gfx); + } + self.current_texture = tex; + } + + pub fn get(&mut self) -> &mut Option{ + &mut self.current_texture + } + + //TODO: Extend for clearing textures + pub fn clear(&mut self/*, gfx: &mut Graphics */){ + /*if let Some(texture) = &mut self.current_texture { + texture.unregister_textures(gfx); + }*/ + self.current_texture = None; + } +} -pub struct TextureResponse2<'a>{ - pub texture: &'a Texture, + +pub struct TextureResponse<'a>{ + pub texture: &'a TexturePair, pub x_offset_texture: i32, pub y_offset_texture: i32, @@ -39,7 +68,13 @@ pub struct TextureResponse2<'a>{ pub y_tex_bottom_global : i32 } +pub struct TexturePair{ + pub texture:Texture, + pub texture_egui: SizedTexture +} + impl TexWrap{ + pub fn from_rgbaimage(gfx: &mut Graphics, settings: &PersistentSettings, image: &RgbaImage) -> Option{ Self::gen_from_rgbaimage(gfx, settings, image, Self::gen_texture_standard) } @@ -49,7 +84,7 @@ impl TexWrap{ } fn gen_texture_standard(gfx: &mut Graphics, bytes:&[u8], width:u32, height:u32, settings: &PersistentSettings, size_ok: bool)-> Option - { + { gfx.create_texture() .from_bytes(bytes, width, height) .with_mipmaps(settings.use_mipmaps&&size_ok) @@ -114,7 +149,7 @@ impl TexWrap{ let col_count = (im_w as f32/max_texture_size as f32).ceil() as u32; let row_count = (im_h as f32/max_texture_size as f32).ceil() as u32; - let mut texture_vec:Vec = Vec::new(); + let mut texture_vec:Vec = Vec::new(); let row_increment = std::cmp::min(max_texture_size, im_h); let col_increment = std::cmp::min(max_texture_size, im_w); let mut fine = true; @@ -137,7 +172,11 @@ impl TexWrap{ let tex = texture_generator_function(gfx, my_img.as_ref(), my_img.width(), my_img.height(), settings, allow_mipmap); if let Some(t) = tex { - texture_vec.push(t); + let egt = gfx.egui_register_texture(&t); + let te = TexturePair{texture: t, texture_egui: egt}; + texture_vec.push(te); + + } else{ //On error texture_vec.clear(); @@ -167,7 +206,7 @@ impl TexWrap{ for col_idx in 0..self.col_count { let translate_x = translation_x as f64+scale as f64*col_idx as f64 *self.col_translation as f64; - draw.image(&self.texture_array[tex_idx]) + draw.image(&self.texture_array[tex_idx].texture) .blend_mode(BlendMode::NORMAL) .scale(scale, scale) .translate(translate_x as f32, translate_y as f32); @@ -176,9 +215,15 @@ impl TexWrap{ } } + pub fn unregister_textures(&mut self, gfx: &mut Graphics){ + for text in &self.texture_array{ + gfx.egui_remove_texture(text.texture_egui.id); + } + } + pub fn update_textures(&mut self, gfx: &mut Graphics, image: &RgbaImage){ if self.col_count==1 && self.row_count==1 { - if let Err(e) = gfx.update_texture(&mut self.texture_array[0]).with_data(image).update() { + if let Err(e) = gfx.update_texture(&mut self.texture_array[0].texture).with_data(image).update() { error!("{e}"); } }else{ @@ -198,7 +243,7 @@ impl TexWrap{ let sub_img = imageops::crop_imm(image, tex_start_x, tex_start_y, tex_width, tex_height); let my_img = sub_img.to_image(); - if let Err(e) = gfx.update_texture(&mut self.texture_array[tex_index]).with_data(my_img.as_ref()).update() { + if let Err(e) = gfx.update_texture(&mut self.texture_array[tex_index].texture).with_data(my_img.as_ref()).update() { error!("{e}"); } tex_index += 1; @@ -207,15 +252,15 @@ impl TexWrap{ } } - pub fn get_texture_at_xy(&self, xa:i32, ya:i32)->TextureResponse2{ + pub fn get_texture_at_xy(&self, xa:i32, ya:i32)->TextureResponse{ let x = xa.max(0).min(self.width() as i32-1); let y = ya.max(0).min(self.height() as i32-1); let x_idx = x /self.col_translation as i32; let y_idx = y /self.row_translation as i32; let tex_idx = (y_idx*self.col_count as i32+x_idx).min(self.texture_array.len() as i32 -1); - let my_tex = &self.texture_array[tex_idx as usize]; - + let my_tex_pair = &self.texture_array[tex_idx as usize]; + let my_tex = &my_tex_pair.texture; let width = my_tex.width() as i32; let height = my_tex.height() as i32; @@ -230,7 +275,7 @@ impl TexWrap{ let remaining_width = width- x_offset_texture; let remaining_height = height - y_offset_texture; - TextureResponse2 {texture: my_tex, + TextureResponse {texture: my_tex_pair, x_offset_texture: x_offset_texture, y_offset_texture: y_offset_texture, diff --git a/src/ui.rs b/src/ui.rs index b5ffce04..dbfbfd7f 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -32,7 +32,6 @@ use notan::{ egui::{self, *}, prelude::{App, Graphics}, }; -use wgpu::TextureUsages; use std::{ collections::BTreeSet, ops::RangeInclusive, @@ -456,7 +455,7 @@ impl EguiExt for Ui { /// Proof-of-concept funtion to draw texture completely with egui #[allow(unused)] pub fn image_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { - if let Some(texture) = &state.current_texture { + if let Some(texture) = &state.current_texture.get() { //let tex_id = gfx.egui_register_texture(&texture.texture_array[0]); //TODO: Adapt if needed let image_rect = Rect::from_center_size( @@ -520,7 +519,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { egui::ScrollArea::vertical().auto_shrink([false,true]) .show(ui, |ui| { - if let Some(texture) = &state.current_texture { + if let Some(texture) = &state.current_texture.get() { let desired_width = PANEL_WIDTH as f64 - PANEL_WIDGET_OFFSET as f64; @@ -591,12 +590,11 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { let bbox_tl: Pos2; let bbox_br: Pos2; if texture.texture_count==1 { - let texture_resonse = texture.get_texture_at_xy(0,0); - let tex_id = gfx.egui_register_texture(texture_resonse.texture); + let texture_resonse = texture.get_texture_at_xy(0,0); ui.add_space(10.); let preview_rect = ui .add( - egui::Image::new(tex_id) + egui::Image::new(texture_resonse.texture.texture_egui) .maintain_aspect_ratio(false) .fit_to_exact_size(egui::Vec2::splat(desired_width as f32)) .rounding(ROUNDING) @@ -610,7 +608,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { bbox_br = preview_rect.right_bottom(); } else{ - (bbox_tl, bbox_br) = render_info_image_tiled(ui, uv_center,uv_size, desired_width, texture, gfx); + (bbox_tl, bbox_br) = render_info_image_tiled(ui, uv_center,uv_size, desired_width, texture); } let bg_color = Color32::BLACK.linear_multiply(0.5); @@ -716,7 +714,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { }); }); - if state.current_texture.is_some() { + if state.current_texture.get().is_some() { ui.styled_collapsing("Alpha tools", |ui| { ui.vertical_centered_justified(|ui| { egui::Frame::none() @@ -731,7 +729,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { .on_hover_text("Highlight pixels with zero alpha and color information") .clicked() { - state.current_texture = highlight_bleed(img).to_texture(gfx, &state.persistent_settings); + state.current_texture.set(highlight_bleed(img).to_texture(gfx, &state.persistent_settings), gfx); } if ui .button("Show semi-transparent pixels") @@ -740,10 +738,11 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { ) .clicked() { - state.current_texture = highlight_semitrans(img).to_texture(gfx, &state.persistent_settings); + + state.current_texture.set(highlight_semitrans(img).to_texture(gfx, &state.persistent_settings), gfx); } if ui.button("Reset image").clicked() { - state.current_texture = img.to_texture(gfx, &state.persistent_settings); + state.current_texture.set(img.to_texture(gfx, &state.persistent_settings), gfx); } } }); @@ -751,7 +750,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { }); } - if state.current_texture.is_some() { + if state.current_texture.get().is_some() { ui.horizontal(|ui| { ui.label("Tiling"); ui.style_mut().spacing.slider_width = ui.available_width() - 16.; @@ -763,7 +762,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { }); } -fn render_info_image_tiled(ui: &mut Ui, uv_center: (f64, f64), uv_size: (f64, f64), desired_width: f64, texture: &crate::texture_wrapper::TexWrap, gfx: &mut Graphics) -> (Pos2, Pos2) { +fn render_info_image_tiled(ui: &mut Ui, uv_center: (f64, f64), uv_size: (f64, f64), desired_width: f64, texture: &crate::texture_wrapper::TexWrap) -> (Pos2, Pos2) { let xy_size = ((texture.width()as f64*uv_size.0) as i32, (texture.height()as f64*uv_size.1) as i32); @@ -827,12 +826,12 @@ fn render_info_image_tiled(ui: &mut Ui, uv_center: (f64, f64), uv_size: (f64, f6 (curr_tex_end.y-curr_tex_response.y_tex_top_global+1) as f64 / curr_tex_response.texture_height as f64); - let tex_id2 = gfx.egui_register_texture(curr_tex_response.texture); + //let tex_id2 = gfx.egui_register_texture(curr_tex_response.texture); let draw_tl_32 = Pos2::new(curr_ui_curs.x as f32, curr_ui_curs.y as f32); let draw_br_32 = Pos2::new((curr_ui_curs.x+display_size.x) as f32, (curr_ui_curs.y+display_size.y) as f32); let r_ret =egui::Rect::from_min_max(draw_tl_32, draw_br_32); - egui::Image::new(tex_id2) + egui::Image::new(curr_tex_response.texture.texture_egui) .maintain_aspect_ratio(false) .fit_to_exact_size(egui::Vec2::new(display_size.x as f32, display_size.y as f32)) .uv(egui::Rect::from_x_y_ranges( @@ -983,18 +982,18 @@ pub fn settings_ui(app: &mut App, ctx: &Context, state: &mut OculanteState, gfx: if ui.styled_checkbox(&mut state.persistent_settings.linear_mag_filter, "Interpolate when zooming in").on_hover_text("When zooming in, do you prefer to see individual pixels or an interpolation?").changed(){ if let Some(img) = &state.current_image { if state.edit_state.result_image_op.is_empty() { - state.current_texture = img.to_texture(gfx, &state.persistent_settings); + state.current_texture.set(img.to_texture(gfx, &state.persistent_settings), gfx); } else { - state.current_texture = state.edit_state.result_pixel_op.to_texture(gfx, &state.persistent_settings); + state.current_texture.set(state.edit_state.result_pixel_op.to_texture(gfx, &state.persistent_settings), gfx); } } } if ui.styled_checkbox(&mut state.persistent_settings.linear_min_filter, "Interpolate when zooming out").on_hover_text("When zooming out, do you prefer crisper or smoother pixels?").changed(){ if let Some(img) = &state.current_image { if state.edit_state.result_image_op.is_empty() { - state.current_texture = img.to_texture(gfx, &state.persistent_settings); + state.current_texture.set(img.to_texture(gfx, &state.persistent_settings), gfx); } else { - state.current_texture = state.edit_state.result_pixel_op.to_texture(gfx, &state.persistent_settings); + state.current_texture.set(state.edit_state.result_pixel_op.to_texture(gfx, &state.persistent_settings), gfx); } } } @@ -1003,9 +1002,9 @@ pub fn settings_ui(app: &mut App, ctx: &Context, state: &mut OculanteState, gfx: if ui.styled_checkbox(&mut state.persistent_settings.use_mipmaps, "Use mipmaps").on_hover_text("When zooming out, less memory will be used. Faster performance, but blurry.").changed(){ if let Some(img) = &state.current_image { if state.edit_state.result_image_op.is_empty() { - state.current_texture = img.to_texture(gfx, &state.persistent_settings); + state.current_texture.set(img.to_texture(gfx, &state.persistent_settings), gfx); } else { - state.current_texture = state.edit_state.result_pixel_op.to_texture(gfx, &state.persistent_settings); + state.current_texture.set(state.edit_state.result_pixel_op.to_texture(gfx, &state.persistent_settings), gfx); } } } @@ -1291,7 +1290,7 @@ pub fn edit_ui(app: &mut App, ctx: &Context, state: &mut OculanteState, gfx: &mu { if let Some(img) = &state.current_image { state.image_geometry.dimensions = img.dimensions(); - state.current_texture = img.to_texture(gfx, &state.persistent_settings); + state.current_texture.set(img.to_texture(gfx, &state.persistent_settings), gfx); } } if ui @@ -1558,15 +1557,14 @@ pub fn edit_ui(app: &mut App, ctx: &Context, state: &mut OculanteState, gfx: &mu } // Update the texture - if let Some(tex) = &mut state.current_texture { + if let Some(tex) = &mut state.current_texture.get() { if let Some(img) = &state.current_image { if tex.width() as u32 == state.edit_state.result_pixel_op.width() && state.edit_state.result_pixel_op.height() == img.height() { state.edit_state.result_pixel_op.update_texture_with_texwrap(gfx, tex); - } else { - state.current_texture = - state.edit_state.result_pixel_op.to_texture(gfx, &state.persistent_settings); + } else { + state.current_texture.set(state.edit_state.result_pixel_op.to_texture(gfx, &state.persistent_settings), gfx); } } } @@ -2352,16 +2350,14 @@ pub fn main_menu(ui: &mut Ui, state: &mut OculanteState, app: &mut App, gfx: &mu if let Some(img) = &state.current_image { match &state.persistent_settings.current_channel { ColorChannel::Rgb => { - state.current_texture = - unpremult(img).to_texture(gfx, &state.persistent_settings) + state.current_texture.set(unpremult(img).to_texture(gfx, &state.persistent_settings), gfx); } ColorChannel::Rgba => { - state.current_texture = img.to_texture(gfx, &state.persistent_settings) + state.current_texture.set(img.to_texture(gfx, &state.persistent_settings), gfx); } _ => { - state.current_texture = - solo_channel(img, state.persistent_settings.current_channel as usize) - .to_texture(gfx, &state.persistent_settings) + state.current_texture.set(solo_channel(img, state.persistent_settings.current_channel as usize) + .to_texture(gfx, &state.persistent_settings), gfx); } } } @@ -2489,7 +2485,7 @@ pub fn main_menu(ui: &mut Ui, state: &mut OculanteState, app: &mut App, gfx: &mu } } - if state.current_texture.is_some() && window_x > ui.cursor().left() + 80. { + if state.current_texture.get().is_some() && window_x > ui.cursor().left() + 80. { if tooltip( unframed_button(PLACEHOLDER, ui), "Clear image", diff --git a/src/utils.rs b/src/utils.rs index 9ffe937a..fd6052c2 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -751,7 +751,7 @@ pub fn clear_image(state: &mut OculanteState) { debug!("Clearing image. Next is {}", next_img.display()); if state.scrubber.entries.len() == 0 { state.current_image = None; - state.current_texture = None; + state.current_texture.clear(); state.current_path = None; state.image_info = None; return; From a39c9c11089e7b758a32d1bfe0ea1c914d6c2e7e Mon Sep 17 00:00:00 2001 From: Johann Woelper Date: Sun, 6 Oct 2024 19:57:43 +0200 Subject: [PATCH 28/29] cargo fmt --- src/appstate.rs | 16 +- src/main.rs | 59 ++++--- src/texture_wrapper.rs | 362 +++++++++++++++++++++++------------------ src/ui.rs | 158 +++++++++++------- src/utils.rs | 13 +- 5 files changed, 359 insertions(+), 249 deletions(-) diff --git a/src/appstate.rs b/src/appstate.rs index 8d0e2c5e..2c04be77 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -1,5 +1,9 @@ use crate::{ - image_editing::EditState, scrubber::Scrubber, settings::{PersistentSettings, VolatileSettings}, texture_wrapper::TextureWrapperManager, utils::{ExtendedImageInfo, Frame, Player} + image_editing::EditState, + scrubber::Scrubber, + settings::{PersistentSettings, VolatileSettings}, + texture_wrapper::TextureWrapperManager, + utils::{ExtendedImageInfo, Frame, Player}, }; use egui_notify::Toasts; @@ -41,11 +45,9 @@ impl Message { } } - - /// The state of the application #[derive(AppState)] -pub struct OculanteState{ +pub struct OculanteState { pub image_geometry: ImageGeometry, pub compare_list: HashMap, pub drag_enabled: bool, @@ -93,7 +95,7 @@ pub struct OculanteState{ pub filebrowser_id: Option, } -impl<'b> OculanteState{ +impl<'b> OculanteState { pub fn send_message_info(&self, msg: &str) { _ = self.message_channel.0.send(Message::info(msg)); } @@ -107,8 +109,8 @@ impl<'b> OculanteState{ } } -impl<'b> Default for OculanteState{ - fn default() -> OculanteState{ +impl<'b> Default for OculanteState { + fn default() -> OculanteState { let tx_channel = mpsc::channel(); OculanteState { image_geometry: ImageGeometry { diff --git a/src/main.rs b/src/main.rs index c03f51c7..c03df956 100644 --- a/src/main.rs +++ b/src/main.rs @@ -207,7 +207,7 @@ fn init(_app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins) -> OculanteSt state.player = Player::new( state.texture_channel.0.clone(), - state.persistent_settings.max_cache + state.persistent_settings.max_cache, ); debug!("matches {:?}", matches); @@ -678,7 +678,7 @@ fn update(app: &mut App, state: &mut OculanteState) { if state.first_start { app.window().set_always_on_top(false); } - + if let Some(p) = &state.current_path { let t = app.timer.elapsed_f32() % 0.8; if t <= 0.05 { @@ -930,30 +930,37 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O state.redraw = false; } } - + if let Some(tex) = &mut state.current_texture.get() { if tex.width() as u32 == img.width() && tex.height() as u32 == img.height() { img.update_texture_with_texwrap(gfx, tex); } else { - state.current_texture.set(img.to_texture(gfx, &state.persistent_settings), gfx); + state + .current_texture + .set(img.to_texture(gfx, &state.persistent_settings), gfx); } } else { debug!("Setting texture"); - state.current_texture.set(img.to_texture(gfx, &state.persistent_settings), gfx); + state + .current_texture + .set(img.to_texture(gfx, &state.persistent_settings), gfx); } match &state.persistent_settings.current_channel { // Unpremultiply the image - ColorChannel::Rgb => { - state.current_texture.set(unpremult(&img).to_texture(gfx, &state.persistent_settings), gfx) - } + ColorChannel::Rgb => state.current_texture.set( + unpremult(&img).to_texture(gfx, &state.persistent_settings), + gfx, + ), // Do nuttin' ColorChannel::Rgba => (), // Display the channel _ => { - - state.current_texture.set(solo_channel(&img, state.persistent_settings.current_channel as usize) - .to_texture(gfx, &state.persistent_settings),gfx); + state.current_texture.set( + solo_channel(&img, state.persistent_settings.current_channel as usize) + .to_texture(gfx, &state.persistent_settings), + gfx, + ); } } state.current_image = Some(img); @@ -1114,22 +1121,29 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O } } if state.tiling < 2 { - texture.draw_textures(&mut draw, + texture.draw_textures( + &mut draw, aligned_offset_x, aligned_offset_y, - state.image_geometry.scale); + state.image_geometry.scale, + ); } else { - for yi in 0..state.tiling { - for xi in 0..state.tiling { + for xi in 0..state.tiling { //The "old" version used only a static offset, is this correct? - let translate_x = (xi as f32* texture.width()*state.image_geometry.scale + state.image_geometry.offset.x).trunc(); - let translate_y = (yi as f32* texture.height()*state.image_geometry.scale + state.image_geometry.offset.y).trunc(); - - texture.draw_textures(&mut draw, + let translate_x = (xi as f32 * texture.width() * state.image_geometry.scale + + state.image_geometry.offset.x) + .trunc(); + let translate_y = (yi as f32 * texture.height() * state.image_geometry.scale + + state.image_geometry.offset.y) + .trunc(); + + texture.draw_textures( + &mut draw, translate_x, translate_y, - state.image_geometry.scale); + state.image_geometry.scale, + ); } } } @@ -1158,10 +1172,7 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O > app.window().size().0 as f32; if show_minimap { - texture.draw_textures(&mut draw, - offset_x, - 100., - scale); + texture.draw_textures(&mut draw, offset_x, 100., scale); } } diff --git a/src/texture_wrapper.rs b/src/texture_wrapper.rs index 7ca30298..56492368 100644 --- a/src/texture_wrapper.rs +++ b/src/texture_wrapper.rs @@ -3,46 +3,44 @@ use notan::draw::*; use notan::egui::EguiRegisterTexture; use notan::egui::SizedTexture; -use crate::Draw; use crate::settings::PersistentSettings; +use crate::Draw; use image::imageops; - use image::RgbaImage; -use notan::prelude::{Graphics, Texture, TextureFilter, BlendMode}; use log::error; - -pub struct TexWrap{ - texture_array:Vec, - pub col_count:u32, - pub row_count:u32, - pub col_translation:u32, - pub row_translation:u32, - pub size_vec:(f32,f32), // The whole Texture Array size - pub texture_count:usize +use notan::prelude::{BlendMode, Graphics, Texture, TextureFilter}; + +pub struct TexWrap { + texture_array: Vec, + pub col_count: u32, + pub row_count: u32, + pub col_translation: u32, + pub row_translation: u32, + pub size_vec: (f32, f32), // The whole Texture Array size + pub texture_count: usize, } #[derive(Default)] -pub struct TextureWrapperManager{ - current_texture: Option +pub struct TextureWrapperManager { + current_texture: Option, } -impl TextureWrapperManager{ - - pub fn set(&mut self, tex: Option,gfx: &mut Graphics){ +impl TextureWrapperManager { + pub fn set(&mut self, tex: Option, gfx: &mut Graphics) { if let Some(texture) = &mut self.current_texture { texture.unregister_textures(gfx); } self.current_texture = tex; } - pub fn get(&mut self) -> &mut Option{ + pub fn get(&mut self) -> &mut Option { &mut self.current_texture } //TODO: Extend for clearing textures - pub fn clear(&mut self/*, gfx: &mut Graphics */){ + pub fn clear(&mut self /*, gfx: &mut Graphics */) { /*if let Some(texture) = &mut self.current_texture { texture.unregister_textures(gfx); }*/ @@ -50,44 +48,56 @@ impl TextureWrapperManager{ } } - -pub struct TextureResponse<'a>{ +pub struct TextureResponse<'a> { pub texture: &'a TexturePair, - pub x_offset_texture: i32, + pub x_offset_texture: i32, pub y_offset_texture: i32, - pub texture_width:i32, - pub texture_height:i32, - pub offset_width:i32, - pub offset_height:i32, + pub texture_width: i32, + pub texture_height: i32, + pub offset_width: i32, + pub offset_height: i32, - pub x_tex_left_global : i32, - pub y_tex_top_global : i32, - pub x_tex_right_global : i32, - pub y_tex_bottom_global : i32 + pub x_tex_left_global: i32, + pub y_tex_top_global: i32, + pub x_tex_right_global: i32, + pub y_tex_bottom_global: i32, } -pub struct TexturePair{ - pub texture:Texture, - pub texture_egui: SizedTexture +pub struct TexturePair { + pub texture: Texture, + pub texture_egui: SizedTexture, } -impl TexWrap{ - - pub fn from_rgbaimage(gfx: &mut Graphics, settings: &PersistentSettings, image: &RgbaImage) -> Option{ +impl TexWrap { + pub fn from_rgbaimage( + gfx: &mut Graphics, + settings: &PersistentSettings, + image: &RgbaImage, + ) -> Option { Self::gen_from_rgbaimage(gfx, settings, image, Self::gen_texture_standard) } - pub fn from_rgbaimage_premult(gfx: &mut Graphics, settings: &PersistentSettings, image: &RgbaImage) -> Option{ + pub fn from_rgbaimage_premult( + gfx: &mut Graphics, + settings: &PersistentSettings, + image: &RgbaImage, + ) -> Option { Self::gen_from_rgbaimage(gfx, settings, image, Self::gen_texture_premult) } - fn gen_texture_standard(gfx: &mut Graphics, bytes:&[u8], width:u32, height:u32, settings: &PersistentSettings, size_ok: bool)-> Option - { + fn gen_texture_standard( + gfx: &mut Graphics, + bytes: &[u8], + width: u32, + height: u32, + settings: &PersistentSettings, + size_ok: bool, + ) -> Option { gfx.create_texture() - .from_bytes(bytes, width, height) - .with_mipmaps(settings.use_mipmaps&&size_ok) + .from_bytes(bytes, width, height) + .with_mipmaps(settings.use_mipmaps && size_ok) // .with_format(notan::prelude::TextureFormat::SRgba8) // .with_premultiplied_alpha() .with_filter( @@ -102,17 +112,23 @@ impl TexWrap{ TextureFilter::Nearest }, ) - // .with_wrap(TextureWrap::Clamp, TextureWrap::Clamp) - .build() - .ok() + // .with_wrap(TextureWrap::Clamp, TextureWrap::Clamp) + .build() + .ok() } - fn gen_texture_premult(gfx: &mut Graphics, bytes:&[u8], width:u32, height:u32, settings: &PersistentSettings, size_ok: bool)-> Option - { + fn gen_texture_premult( + gfx: &mut Graphics, + bytes: &[u8], + width: u32, + height: u32, + settings: &PersistentSettings, + size_ok: bool, + ) -> Option { gfx.create_texture() - .from_bytes(bytes, width, height) - .with_premultiplied_alpha() - .with_mipmaps(settings.use_mipmaps&&size_ok) + .from_bytes(bytes, width, height) + .with_premultiplied_alpha() + .with_mipmaps(settings.use_mipmaps && size_ok) // .with_format(notan::prelude::TextureFormat::SRgba8) // .with_premultiplied_alpha() .with_filter( @@ -127,123 +143,159 @@ impl TexWrap{ TextureFilter::Nearest }, ) - // .with_wrap(TextureWrap::Clamp, TextureWrap::Clamp) - .build() - .ok() + // .with_wrap(TextureWrap::Clamp, TextureWrap::Clamp) + .build() + .ok() } - fn gen_from_rgbaimage(gfx: &mut Graphics, settings: &PersistentSettings, image: &RgbaImage, texture_generator_function: fn (&mut Graphics, &[u8], u32, u32, &PersistentSettings, bool)-> Option) -> Option{ - const MAX_PIXEL_COUNT:usize = 8192*8192; + fn gen_from_rgbaimage( + gfx: &mut Graphics, + settings: &PersistentSettings, + image: &RgbaImage, + texture_generator_function: fn( + &mut Graphics, + &[u8], + u32, + u32, + &PersistentSettings, + bool, + ) -> Option, + ) -> Option { + const MAX_PIXEL_COUNT: usize = 8192 * 8192; let im_w = image.width(); let im_h = image.height(); - let im_pixel_count = (im_w*im_h) as usize; + let im_pixel_count = (im_w * im_h) as usize; let allow_mipmap = im_pixel_count < MAX_PIXEL_COUNT; if !allow_mipmap { - warn!("Image with {0} pixels too large (max {1} pixels), disabling mipmaps", im_pixel_count, MAX_PIXEL_COUNT); + warn!( + "Image with {0} pixels too large (max {1} pixels), disabling mipmaps", + im_pixel_count, MAX_PIXEL_COUNT + ); } let im_size = (im_w as f32, im_h as f32); - let max_texture_size = gfx.limits().max_texture_size; - let col_count = (im_w as f32/max_texture_size as f32).ceil() as u32; - let row_count = (im_h as f32/max_texture_size as f32).ceil() as u32; + let max_texture_size = gfx.limits().max_texture_size; + let col_count = (im_w as f32 / max_texture_size as f32).ceil() as u32; + let row_count = (im_h as f32 / max_texture_size as f32).ceil() as u32; - let mut texture_vec:Vec = Vec::new(); + let mut texture_vec: Vec = Vec::new(); let row_increment = std::cmp::min(max_texture_size, im_h); let col_increment = std::cmp::min(max_texture_size, im_w); let mut fine = true; - - for row_index in 0..row_count { - let tex_start_y = row_index*row_increment; - let tex_height = std::cmp::min( - row_increment, - im_h-tex_start_y - ); - for col_index in 0..col_count { - let tex_start_x = col_index*col_increment; - let tex_width = std::cmp::min( - col_increment, - im_w-tex_start_x - ); - - let sub_img = imageops::crop_imm(image, tex_start_x, tex_start_y, tex_width, tex_height); + + for row_index in 0..row_count { + let tex_start_y = row_index * row_increment; + let tex_height = std::cmp::min(row_increment, im_h - tex_start_y); + for col_index in 0..col_count { + let tex_start_x = col_index * col_increment; + let tex_width = std::cmp::min(col_increment, im_w - tex_start_x); + + let sub_img = + imageops::crop_imm(image, tex_start_x, tex_start_y, tex_width, tex_height); let my_img = sub_img.to_image(); - let tex = texture_generator_function(gfx, my_img.as_ref(), my_img.width(), my_img.height(), settings, allow_mipmap); - - if let Some(t) = tex { - let egt = gfx.egui_register_texture(&t); - let te = TexturePair{texture: t, texture_egui: egt}; - texture_vec.push(te); - - - } - else{ //On error - texture_vec.clear(); - fine = false; - break; - } + let tex = texture_generator_function( + gfx, + my_img.as_ref(), + my_img.width(), + my_img.height(), + settings, + allow_mipmap, + ); + + if let Some(t) = tex { + let egt = gfx.egui_register_texture(&t); + let te = TexturePair { + texture: t, + texture_egui: egt, + }; + texture_vec.push(te); + } else { + //On error + texture_vec.clear(); + fine = false; + break; + } } - if !fine{//early exit if we failed + if !fine { + //early exit if we failed break; } } - + if fine { - let texture_count = texture_vec.len(); - Some(TexWrap {size_vec:im_size, col_count:col_count, row_count:row_count,texture_array:texture_vec, col_translation:col_increment, row_translation:row_increment, texture_count}) - } - else { - None - } + let texture_count = texture_vec.len(); + Some(TexWrap { + size_vec: im_size, + col_count: col_count, + row_count: row_count, + texture_array: texture_vec, + col_translation: col_increment, + row_translation: row_increment, + texture_count, + }) + } else { + None + } } - pub fn draw_textures(&self,draw: &mut Draw, translation_x:f32, translation_y:f32, scale: f32){ + pub fn draw_textures( + &self, + draw: &mut Draw, + translation_x: f32, + translation_y: f32, + scale: f32, + ) { let mut tex_idx = 0; - for row_idx in 0..self.row_count - { - let translate_y = translation_y as f64+scale as f64*row_idx as f64*self.row_translation as f64; - for col_idx in 0..self.col_count - { - let translate_x = translation_x as f64+scale as f64*col_idx as f64 *self.col_translation as f64; - draw.image(&self.texture_array[tex_idx].texture) - .blend_mode(BlendMode::NORMAL) - .scale(scale, scale) - .translate(translate_x as f32, translate_y as f32); - tex_idx += 1; - } + for row_idx in 0..self.row_count { + let translate_y = + translation_y as f64 + scale as f64 * row_idx as f64 * self.row_translation as f64; + for col_idx in 0..self.col_count { + let translate_x = translation_x as f64 + + scale as f64 * col_idx as f64 * self.col_translation as f64; + draw.image(&self.texture_array[tex_idx].texture) + .blend_mode(BlendMode::NORMAL) + .scale(scale, scale) + .translate(translate_x as f32, translate_y as f32); + tex_idx += 1; } + } } - pub fn unregister_textures(&mut self, gfx: &mut Graphics){ - for text in &self.texture_array{ + pub fn unregister_textures(&mut self, gfx: &mut Graphics) { + for text in &self.texture_array { gfx.egui_remove_texture(text.texture_egui.id); } } - pub fn update_textures(&mut self, gfx: &mut Graphics, image: &RgbaImage){ - if self.col_count==1 && self.row_count==1 { - if let Err(e) = gfx.update_texture(&mut self.texture_array[0].texture).with_data(image).update() { + pub fn update_textures(&mut self, gfx: &mut Graphics, image: &RgbaImage) { + if self.col_count == 1 && self.row_count == 1 { + if let Err(e) = gfx + .update_texture(&mut self.texture_array[0].texture) + .with_data(image) + .update() + { error!("{e}"); } - }else{ + } else { let mut tex_index = 0; - for row_index in 0..self.row_count { - let tex_start_y = row_index*self.row_translation; - let tex_height = std::cmp::min( - self.row_translation, - image.height()-tex_start_y - ); - for col_index in 0..self.col_count { - let tex_start_x = col_index*self.col_translation; - let tex_width = std::cmp::min( - self.col_translation, - image.width()-tex_start_x - ); - - let sub_img = imageops::crop_imm(image, tex_start_x, tex_start_y, tex_width, tex_height); + for row_index in 0..self.row_count { + let tex_start_y = row_index * self.row_translation; + let tex_height = std::cmp::min(self.row_translation, image.height() - tex_start_y); + for col_index in 0..self.col_count { + let tex_start_x = col_index * self.col_translation; + let tex_width = + std::cmp::min(self.col_translation, image.width() - tex_start_x); + + let sub_img = + imageops::crop_imm(image, tex_start_x, tex_start_y, tex_width, tex_height); let my_img = sub_img.to_image(); - if let Err(e) = gfx.update_texture(&mut self.texture_array[tex_index].texture).with_data(my_img.as_ref()).update() { + if let Err(e) = gfx + .update_texture(&mut self.texture_array[tex_index].texture) + .with_data(my_img.as_ref()) + .update() + { error!("{e}"); } tex_index += 1; @@ -252,31 +304,33 @@ impl TexWrap{ } } - pub fn get_texture_at_xy(&self, xa:i32, ya:i32)->TextureResponse{ - let x = xa.max(0).min(self.width() as i32-1); - let y = ya.max(0).min(self.height() as i32-1); + pub fn get_texture_at_xy(&self, xa: i32, ya: i32) -> TextureResponse { + let x = xa.max(0).min(self.width() as i32 - 1); + let y = ya.max(0).min(self.height() as i32 - 1); - let x_idx = x /self.col_translation as i32; - let y_idx = y /self.row_translation as i32; - let tex_idx = (y_idx*self.col_count as i32+x_idx).min(self.texture_array.len() as i32 -1); + let x_idx = x / self.col_translation as i32; + let y_idx = y / self.row_translation as i32; + let tex_idx = + (y_idx * self.col_count as i32 + x_idx).min(self.texture_array.len() as i32 - 1); let my_tex_pair = &self.texture_array[tex_idx as usize]; let my_tex = &my_tex_pair.texture; let width = my_tex.width() as i32; let height = my_tex.height() as i32; - let tex_left = x_idx*self.col_translation as i32; - let tex_top = y_idx*self.row_translation as i32; - let tex_right = tex_left+width-1; - let tex_bottom = tex_top+height-1; - - let x_offset_texture = xa-tex_left; - let y_offset_texture = ya-tex_top; + let tex_left = x_idx * self.col_translation as i32; + let tex_top = y_idx * self.row_translation as i32; + let tex_right = tex_left + width - 1; + let tex_bottom = tex_top + height - 1; + + let x_offset_texture = xa - tex_left; + let y_offset_texture = ya - tex_top; - let remaining_width = width- x_offset_texture; + let remaining_width = width - x_offset_texture; let remaining_height = height - y_offset_texture; - TextureResponse {texture: my_tex_pair, - x_offset_texture: x_offset_texture, + TextureResponse { + texture: my_tex_pair, + x_offset_texture: x_offset_texture, y_offset_texture: y_offset_texture, texture_width: width, @@ -287,20 +341,20 @@ impl TexWrap{ x_tex_right_global: tex_right, y_tex_bottom_global: tex_bottom, - offset_width: remaining_width, - offset_height: remaining_height - } + offset_width: remaining_width, + offset_height: remaining_height, + } } - pub fn size(&self)->(f32,f32){ + pub fn size(&self) -> (f32, f32) { return self.size_vec; } - pub fn width(&self)-> f32 { + pub fn width(&self) -> f32 { return self.size_vec.0; } - pub fn height(&self)-> f32 { + pub fn height(&self) -> f32 { return self.size_vec.1; } -} \ No newline at end of file +} diff --git a/src/ui.rs b/src/ui.rs index dbfbfd7f..1f1f45b9 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -520,7 +520,7 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { egui::ScrollArea::vertical().auto_shrink([false,true]) .show(ui, |ui| { if let Some(texture) = &state.current_texture.get() { - + let desired_width = PANEL_WIDTH as f64 - PANEL_WIDGET_OFFSET as f64; let scale = (desired_width / 8.) / texture.size().0 as f64; @@ -583,14 +583,14 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { ); ui.end_row(); }); - + // make sure aspect ratio is compensated for the square preview let ratio = texture.size().0 as f64 / texture.size().1 as f64; - let uv_size = (scale, scale * ratio); + let uv_size = (scale, scale * ratio); let bbox_tl: Pos2; let bbox_br: Pos2; if texture.texture_count==1 { - let texture_resonse = texture.get_texture_at_xy(0,0); + let texture_resonse = texture.get_texture_at_xy(0,0); ui.add_space(10.); let preview_rect = ui .add( @@ -612,12 +612,12 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { } let bg_color = Color32::BLACK.linear_multiply(0.5); - let preview_rect = egui::Rect::from_min_max(bbox_tl, bbox_br); + let preview_rect = egui::Rect::from_min_max(bbox_tl, bbox_br); ui.advance_cursor_after_rect(preview_rect); - + let stroke_color = Color32::from_white_alpha(240); - + ui.painter_at(preview_rect).line_segment( [preview_rect.center_bottom(), preview_rect.center_top()], Stroke::new(4., bg_color), @@ -762,13 +762,26 @@ pub fn info_ui(ctx: &Context, state: &mut OculanteState, gfx: &mut Graphics) { }); } -fn render_info_image_tiled(ui: &mut Ui, uv_center: (f64, f64), uv_size: (f64, f64), desired_width: f64, texture: &crate::texture_wrapper::TexWrap) -> (Pos2, Pos2) { - let xy_size = ((texture.width()as f64*uv_size.0) as i32, - (texture.height()as f64*uv_size.1) as i32); +fn render_info_image_tiled( + ui: &mut Ui, + uv_center: (f64, f64), + uv_size: (f64, f64), + desired_width: f64, + texture: &crate::texture_wrapper::TexWrap, +) -> (Pos2, Pos2) { + let xy_size = ( + (texture.width() as f64 * uv_size.0) as i32, + (texture.height() as f64 * uv_size.1) as i32, + ); - let xy_center = ((texture.width() as f64*uv_center.0) as i32, (texture.height() as f64*uv_center.1) as i32); //(16384,1024);// - let sc1 = (2.0*xy_size.0 as f64 / desired_width, - 2.0*xy_size.1 as f64 / desired_width); + let xy_center = ( + (texture.width() as f64 * uv_center.0) as i32, + (texture.height() as f64 * uv_center.1) as i32, + ); //(16384,1024);// + let sc1 = ( + 2.0 * xy_size.0 as f64 / desired_width, + 2.0 * xy_size.1 as f64 / desired_width, + ); //coordinates of the image-view let mut bbox_tl = egui::pos2(f32::MAX, f32::MAX); @@ -778,78 +791,101 @@ fn render_info_image_tiled(ui: &mut Ui, uv_center: (f64, f64), uv_size: (f64, f6 let base_ui_curs = nalgebra::Vector2::new(ui.cursor().min.x as f64, ui.cursor().min.y as f64); let mut curr_ui_curs = base_ui_curs; //our start position - + //Loop control variables, start end end coordinates of interest - let x_coordinate_end = (xy_center.0+xy_size.0) as i32; - let mut y_coordinate = xy_center.1-xy_size.1; - let y_coordinate_end = (xy_center.1+xy_size.1) as i32; + let x_coordinate_end = (xy_center.0 + xy_size.0) as i32; + let mut y_coordinate = xy_center.1 - xy_size.1; + let y_coordinate_end = (xy_center.1 + xy_size.1) as i32; - while y_coordinate<=y_coordinate_end { + while y_coordinate <= y_coordinate_end { let mut y_coordinate_increment = 0; //increment for y coordinate after x loop - let mut x_coordinate = xy_center.0-xy_size.0; + let mut x_coordinate = xy_center.0 - xy_size.0; curr_ui_curs.x = base_ui_curs.x; let mut last_display_size_y: f64 = 0.0; - while x_coordinate<=x_coordinate_end { + while x_coordinate <= x_coordinate_end { //get texture tile - let curr_tex_response = texture.get_texture_at_xy(x_coordinate as i32, y_coordinate as i32); - + let curr_tex_response = + texture.get_texture_at_xy(x_coordinate as i32, y_coordinate as i32); + //increment coordinates by usable width/height y_coordinate_increment = curr_tex_response.offset_height; x_coordinate += curr_tex_response.offset_width; //Handling last texture in a row or col - let mut curr_tex_end = nalgebra::Vector2::new(i32::min(curr_tex_response.x_tex_right_global, x_coordinate_end), i32::min(curr_tex_response.y_tex_bottom_global, y_coordinate_end)); + let mut curr_tex_end = nalgebra::Vector2::new( + i32::min(curr_tex_response.x_tex_right_global, x_coordinate_end), + i32::min(curr_tex_response.y_tex_bottom_global, y_coordinate_end), + ); //Handling positive coordinate overflow - if curr_tex_response.x_tex_right_global as f32>= texture.width()-1.0f32 { - x_coordinate = x_coordinate_end+1; - curr_tex_end.x += (x_coordinate_end-curr_tex_response.x_tex_right_global).max(0); + if curr_tex_response.x_tex_right_global as f32 >= texture.width() - 1.0f32 { + x_coordinate = x_coordinate_end + 1; + curr_tex_end.x += (x_coordinate_end - curr_tex_response.x_tex_right_global).max(0); } - if curr_tex_response.y_tex_bottom_global as f32>= texture.height()-1.0f32 { - y_coordinate_increment = y_coordinate_end-y_coordinate+1; - curr_tex_end.y += (y_coordinate_end-curr_tex_response.y_tex_bottom_global).max(0); - } + if curr_tex_response.y_tex_bottom_global as f32 >= texture.height() - 1.0f32 { + y_coordinate_increment = y_coordinate_end - y_coordinate + 1; + curr_tex_end.y += (y_coordinate_end - curr_tex_response.y_tex_bottom_global).max(0); + } //Usable tile size, depending on offsets - let tile_size = nalgebra::Vector2::new(curr_tex_end.x-curr_tex_response.x_offset_texture-curr_tex_response.x_tex_left_global+1, - curr_tex_end.y-curr_tex_response.y_offset_texture-curr_tex_response.y_tex_top_global+1); + let tile_size = nalgebra::Vector2::new( + curr_tex_end.x + - curr_tex_response.x_offset_texture + - curr_tex_response.x_tex_left_global + + 1, + curr_tex_end.y + - curr_tex_response.y_offset_texture + - curr_tex_response.y_tex_top_global + + 1, + ); //Display size - tile size scaled - let display_size = nalgebra::Vector2::new(tile_size.x as f64/sc1.0,tile_size.y as f64/sc1.1); + let display_size = + nalgebra::Vector2::new(tile_size.x as f64 / sc1.0, tile_size.y as f64 / sc1.1); //Texture display range - let uv_start = nalgebra::Vector2::new(curr_tex_response.x_offset_texture as f64 / curr_tex_response.texture_width as f64, - curr_tex_response.y_offset_texture as f64 / curr_tex_response.texture_height as f64); - - let uv_end = nalgebra::Vector2::new((curr_tex_end.x-curr_tex_response.x_tex_left_global+1) as f64 / curr_tex_response.texture_width as f64, - (curr_tex_end.y-curr_tex_response.y_tex_top_global+1) as f64 / curr_tex_response.texture_height as f64); + let uv_start = nalgebra::Vector2::new( + curr_tex_response.x_offset_texture as f64 / curr_tex_response.texture_width as f64, + curr_tex_response.y_offset_texture as f64 / curr_tex_response.texture_height as f64, + ); + let uv_end = nalgebra::Vector2::new( + (curr_tex_end.x - curr_tex_response.x_tex_left_global + 1) as f64 + / curr_tex_response.texture_width as f64, + (curr_tex_end.y - curr_tex_response.y_tex_top_global + 1) as f64 + / curr_tex_response.texture_height as f64, + ); //let tex_id2 = gfx.egui_register_texture(curr_tex_response.texture); - let draw_tl_32 = Pos2::new(curr_ui_curs.x as f32, curr_ui_curs.y as f32); - let draw_br_32 = Pos2::new((curr_ui_curs.x+display_size.x) as f32, (curr_ui_curs.y+display_size.y) as f32); - let r_ret =egui::Rect::from_min_max(draw_tl_32, draw_br_32); + let draw_tl_32 = Pos2::new(curr_ui_curs.x as f32, curr_ui_curs.y as f32); + let draw_br_32 = Pos2::new( + (curr_ui_curs.x + display_size.x) as f32, + (curr_ui_curs.y + display_size.y) as f32, + ); + let r_ret = egui::Rect::from_min_max(draw_tl_32, draw_br_32); egui::Image::new(curr_tex_response.texture.texture_egui) - .maintain_aspect_ratio(false) - .fit_to_exact_size(egui::Vec2::new(display_size.x as f32, display_size.y as f32)) - .uv(egui::Rect::from_x_y_ranges( - uv_start.x as f32 ..=uv_end.x as f32, - uv_start.y as f32 ..=uv_end.y as f32) - ) - .paint_at(ui, r_ret); - + .maintain_aspect_ratio(false) + .fit_to_exact_size(egui::Vec2::new( + display_size.x as f32, + display_size.y as f32, + )) + .uv(egui::Rect::from_x_y_ranges( + uv_start.x as f32..=uv_end.x as f32, + uv_start.y as f32..=uv_end.y as f32, + )) + .paint_at(ui, r_ret); + //Update display cursor curr_ui_curs.x += display_size.x; last_display_size_y = display_size.y; - - //Update coordinates for preview rectangle + + //Update coordinates for preview rectangle bbox_tl.x = bbox_tl.x.min(r_ret.left()); bbox_tl.y = bbox_tl.y.min(r_ret.top()); bbox_br.x = bbox_br.x.max(r_ret.right()); bbox_br.y = bbox_br.y.max(r_ret.bottom()); - } //Update y coordinates y_coordinate += y_coordinate_increment; @@ -1563,7 +1599,7 @@ pub fn edit_ui(app: &mut App, ctx: &Context, state: &mut OculanteState, gfx: &mu && state.edit_state.result_pixel_op.height() == img.height() { state.edit_state.result_pixel_op.update_texture_with_texwrap(gfx, tex); - } else { + } else { state.current_texture.set(state.edit_state.result_pixel_op.to_texture(gfx, &state.persistent_settings), gfx); } } @@ -2350,14 +2386,22 @@ pub fn main_menu(ui: &mut Ui, state: &mut OculanteState, app: &mut App, gfx: &mu if let Some(img) = &state.current_image { match &state.persistent_settings.current_channel { ColorChannel::Rgb => { - state.current_texture.set(unpremult(img).to_texture(gfx, &state.persistent_settings), gfx); + state.current_texture.set( + unpremult(img).to_texture(gfx, &state.persistent_settings), + gfx, + ); } ColorChannel::Rgba => { - state.current_texture.set(img.to_texture(gfx, &state.persistent_settings), gfx); + state + .current_texture + .set(img.to_texture(gfx, &state.persistent_settings), gfx); } _ => { - state.current_texture.set(solo_channel(img, state.persistent_settings.current_channel as usize) - .to_texture(gfx, &state.persistent_settings), gfx); + state.current_texture.set( + solo_channel(img, state.persistent_settings.current_channel as usize) + .to_texture(gfx, &state.persistent_settings), + gfx, + ); } } } diff --git a/src/utils.rs b/src/utils.rs index 46db655f..1689e982 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -289,7 +289,7 @@ impl Player { img_location, self.image_sender.clone(), message_sender, - stop_receiver + stop_receiver, ); if let Ok(meta) = std::fs::metadata(img_location) { @@ -312,7 +312,7 @@ pub fn send_image_threaded( img_location: &Path, texture_sender: Sender, message_sender: Sender, - stop_receiver: Receiver<()> + stop_receiver: Receiver<()>, ) { let loc = img_location.to_owned(); @@ -326,14 +326,14 @@ pub fn send_image_threaded( debug!("Got a frame receiver from opening image"); // _ = texture_sender // .clone() - // .send(Frame::new_reset(f.buffer.clone())); + // .send(Frame::new_reset(f.buffer.clone())); let mut first = true; for f in frame_receiver.iter() { if stop_receiver.try_recv().is_ok() { debug!("Stopped from receiver."); return; - } + } // a "normal image (no animation)" if f.source == FrameSource::Still { debug!("Received image in {:?}", timer.elapsed()); @@ -651,8 +651,7 @@ impl ImageExt for RgbaImage { Vector2::new(self.width() as f32, self.height() as f32) } - - fn to_texture(&self, gfx: &mut Graphics, settings: &PersistentSettings) -> Option { + fn to_texture(&self, gfx: &mut Graphics, settings: &PersistentSettings) -> Option { TexWrap::from_rgbaimage(gfx, settings, self) } @@ -673,7 +672,7 @@ impl ImageExt for RgbaImage { } fn update_texture_with_texwrap(&self, gfx: &mut Graphics, texture: &mut TexWrap) { - texture.update_textures(gfx,self); + texture.update_textures(gfx, self); } } From ef9c5f71e07d1ad21290a441c100eb3796f8585f Mon Sep 17 00:00:00 2001 From: Johann Woelper Date: Mon, 21 Oct 2024 08:33:17 +0200 Subject: [PATCH 29/29] update lockfile --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 1089c705..7ddd4c33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1252,7 +1252,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdbd1f579714e3c809ebd822c81ef148b1ceaeb3d535352afc73fd0c4c6a0017" dependencies = [ "bitflags 2.6.0", - "libloading 0.8.5", + "libloading 0.7.4", "winapi", ]