Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

609 channel picker with shader #624

Merged
merged 16 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 0 additions & 19 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -953,25 +953,6 @@ fn drawe(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut O
state
.current_texture
.set_image(&img, gfx, &state.persistent_settings);

match &state.persistent_settings.current_channel {
// Unpremultiply the image
ColorChannel::Rgb => state.current_texture.set_image(
&unpremult(&img),
gfx,
&state.persistent_settings,
),
// Do nuttin'
ColorChannel::Rgba => (),
// Display the channel
_ => {
state.current_texture.set_image(
&solo_channel(&img, state.persistent_settings.current_channel as usize),
gfx,
&state.persistent_settings,
);
}
}
state.current_image = Some(img);
}
Frame::UpdateTexture => {
Expand Down
172 changes: 152 additions & 20 deletions src/texture_wrapper.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use crate::settings::PersistentSettings;
use crate::utils::ColorChannel;
use image::imageops;
use image::DynamicImage;
use log::debug;
use log::error;
use log::warn;
use notan::draw::*;
use notan::prelude::{BlendMode, Graphics, ShaderSource, Texture, TextureFilter};
use notan::math::{Mat4, Vec4};
use notan::prelude::{BlendMode, Buffer, Graphics, ShaderSource, Texture, TextureFilter};
pub struct TexWrap {
texture_array: Vec<Texture>,
texture_boundary: Texture,
Expand All @@ -18,6 +20,8 @@ pub struct TexWrap {
pipeline: Option<notan::prelude::Pipeline>,
pub format: notan::prelude::TextureFormat,
pub image_format: image::ColorType,
uniform_swizzle_mask: Buffer,
uniform_offset_vec: Buffer,
}

#[derive(Default)]
Expand Down Expand Up @@ -50,7 +54,78 @@ impl TextureWrapperManager {
debug!("Updating or creating texture with new size.");
}

self.current_texture = TexWrap::from_dynamic_image(gfx, settings, img);
let (swizzle_mat, offset_vec) = Self::get_mat_vec(settings.current_channel, img.color());
self.current_texture =
TexWrap::from_dynamic_image(gfx, settings, img, swizzle_mat, offset_vec);
}

pub fn update_color_selection(&mut self, gfx: &mut Graphics, settings: &PersistentSettings) {
if let Some(tex) = &mut self.current_texture {
let (mask, vec) = Self::get_mat_vec(settings.current_channel, tex.image_format);
tex.update_uniform_buffer(gfx, mask, vec);
}
}

fn get_mat_vec(channel_selection: ColorChannel, image_color: image::ColorType) -> (Mat4, Vec4) {
//Currently we have two types of textures: rgba and gray ones.
//All other types will be converted to rgba, so we only need to take care of those types here
if image_color == image::ColorType::L8 || image_color == image::ColorType::L16 {
Self::get_mat_vec_gray(channel_selection)
} else {
Self::get_mat_vec_rgba(channel_selection)
}
}

fn get_mat_vec_gray(channel_selection: ColorChannel) -> (Mat4, Vec4) {
let mut swizzle_mat = Mat4::ZERO;
let mut offset_vec = Vec4::ZERO;
match channel_selection {
ColorChannel::Alpha => {
offset_vec = Vec4::ONE; // Just plain white
}
_ => {
//Every channel is the same, so we don't care
swizzle_mat.x_axis = Vec4::new(1.0, 1.0, 1.0, 0.0);
offset_vec.w = 1.0; //Alpha constant 1.0
}
}
(swizzle_mat, offset_vec)
}

fn get_mat_vec_rgba(channel_selection: ColorChannel) -> (Mat4, Vec4) {
let mut swizzle_mat = Mat4::ZERO;
let mut offset_vec = Vec4::ZERO;

let one_row_vec = Vec4::new(1.0, 1.0, 1.0, 0.0);
match channel_selection {
ColorChannel::Red => {
swizzle_mat.x_axis = one_row_vec;
offset_vec.w = 1.0; //Alpha constant 1.0
}
ColorChannel::Green => {
swizzle_mat.y_axis = one_row_vec;
offset_vec.w = 1.0; //Alpha constant 1.0
}

ColorChannel::Blue => {
swizzle_mat.z_axis = one_row_vec;
offset_vec.w = 1.0; //Alpha constant 1.0
}
ColorChannel::Alpha => {
swizzle_mat.w_axis = one_row_vec;
offset_vec.w = 1.0; //Alpha constant 1.0
}
ColorChannel::Rgb => {
swizzle_mat = Mat4::from_rotation_x(0.0); //Diag
swizzle_mat.w_axis = Vec4::new(0.0, 0.0, 0.0, 0.0); // Kill alpha
offset_vec.w = 1.0; //Alpha constant 1.0
}
ColorChannel::Rgba => {
swizzle_mat = Mat4::from_rotation_x(0.0); //Diag
}
}

(swizzle_mat, offset_vec)
}

pub fn get(&mut self) -> &mut Option<TexWrap> {
Expand All @@ -62,20 +137,18 @@ impl TextureWrapperManager {
}
}

pub struct TextureResponse<'a> {
struct TextureResponse<'a> {
pub texture: &'a Texture,

pub x_offset_texture: i32,
pub y_offset_texture: 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 is_boundary: bool,
}

//language=glsl
const FRAGMENT_GRAYSCALE: ShaderSource = notan::fragment_shader! {
const FRAGMENT_IMAGE_RENDER: ShaderSource = notan::fragment_shader! {
r#"
#version 450
precision mediump float;
Expand All @@ -85,11 +158,19 @@ const FRAGMENT_GRAYSCALE: ShaderSource = notan::fragment_shader! {

layout(binding = 0) uniform sampler2D u_texture;

layout(binding = 1) uniform SwizzleMask {
mat4 swizzle_mat;
};

layout(binding = 2) uniform OffsetVector {
vec4 offset;
};

layout(location = 0) out vec4 color;

void main() {
vec4 tex_col = texture(u_texture, v_uvs);
color = vec4(tex_col.r, tex_col.r,tex_col.r, 1.0) * v_color;
color = ((swizzle_mat*tex_col)+offset) * v_color;
}
"#
};
Expand All @@ -99,8 +180,42 @@ impl TexWrap {
gfx: &mut Graphics,
settings: &PersistentSettings,
image: &DynamicImage,
swizzle_mask: Mat4,
offset_vec: Vec4,
) -> Option<TexWrap> {
Self::gen_from_dynamic_image(gfx, settings, image, Self::gen_texture_standard)
Self::gen_from_dynamic_image(
gfx,
settings,
image,
Self::gen_texture_standard,
swizzle_mask,
offset_vec,
)
}

fn gen_uniform_buffer_swizzle_mask(
gfx: &mut Graphics,
swizzle_mask: Mat4,
offset_vec: Vec4,
) -> (Buffer, Buffer) {
let uniform_swizzle_mask = gfx
.create_uniform_buffer(1, "SwizzleMask")
.with_data(&swizzle_mask)
.build()
.unwrap();

let uniform_offset_vector = gfx
.create_uniform_buffer(2, "OffsetVector")
.with_data(&offset_vec)
.build()
.unwrap();

(uniform_swizzle_mask, uniform_offset_vector)
}

fn update_uniform_buffer(&self, gfx: &mut Graphics, swizzle_mat: Mat4, offset_vec: Vec4) {
gfx.set_buffer_data(&self.uniform_swizzle_mask, &swizzle_mat);
gfx.set_buffer_data(&self.uniform_offset_vec, &offset_vec);
}

fn gen_texture_standard(
Expand Down Expand Up @@ -410,17 +525,18 @@ impl TexWrap {
Option<notan::prelude::Pipeline>,
) {
let mut format: notan::prelude::TextureFormat = notan::app::TextureFormat::Rgba32;
let mut pipeline: Option<notan::prelude::Pipeline> = None;
let pipeline: Option<notan::prelude::Pipeline> =
Some(create_image_pipeline(gfx, Some(&FRAGMENT_IMAGE_RENDER)).unwrap());
debug!("{:?}", image.color());
match image.color() {
image::ColorType::L8 => {
format = notan::prelude::TextureFormat::R8;
pipeline = Some(create_image_pipeline(gfx, Some(&FRAGMENT_GRAYSCALE)).unwrap());
//pipeline = Some(create_image_pipeline(gfx, Some(&FRAGMENT_GRAYSCALE)).unwrap());
}
//TODO: Re-Enable when 16 Bit is implemented in notan
/*image::ColorType::L16 => {
format = notan::prelude::TextureFormat::R16Uint;
pipeline = Some(create_image_pipeline(gfx, Some(&FRAGMENT_GRAYSCALE)).unwrap());
//pipeline = Some(create_image_pipeline(gfx, Some(&FRAGMENT_GRAYSCALE)).unwrap());
}*/
image::ColorType::Rgba32F => {
format = notan::prelude::TextureFormat::Rgba32Float;
Expand Down Expand Up @@ -449,6 +565,8 @@ impl TexWrap {
&PersistentSettings,
bool,
) -> Option<Texture>,
swizzle_mask: Mat4,
add_vec: Vec4,
) -> Option<TexWrap> {
const MAX_PIXEL_COUNT: usize = 8192 * 8192;

Expand Down Expand Up @@ -552,6 +670,8 @@ impl TexWrap {

if fine {
let texture_count = texture_vec.len();
let (uniforms, uniforms2) =
Self::gen_uniform_buffer_swizzle_mask(gfx, swizzle_mask, add_vec);
Some(TexWrap {
texture_boundary: texture_boundary.unwrap(),
size_vec: im_size,
Expand All @@ -564,6 +684,8 @@ impl TexWrap {
pipeline,
format,
image_format: image.color(),
uniform_swizzle_mask: uniforms,
uniform_offset_vec: uniforms2,
})
} else {
None
Expand Down Expand Up @@ -606,7 +728,7 @@ impl TexWrap {
center: (f32, f32),
scale: f32,
) {
self.add_draw_shader(draw);
let mut shader_active = false;

let width_tex = (width / scale) as i32;

Expand All @@ -633,6 +755,15 @@ impl TexWrap {
let curr_tex_response =
self.get_texture_at_xy(x_coordinate as i32, y_coordinate as i32);

//Render boundary without our shader
if !shader_active && !curr_tex_response.is_boundary {
self.add_draw_shader(draw);
shader_active = true;
} else if shader_active && curr_tex_response.is_boundary {
self.remove_draw_shader(draw);
shader_active = false;
}

//print!("x: {} y: {} ", x_coordinate, y_coordinate);
//print!("top: {} left: {} ", curr_tex_response.y_tex_top_global, curr_tex_response.x_tex_left_global);
//print!("bottom: {} right: {} \n", curr_tex_response.y_tex_bottom_global, curr_tex_response.x_tex_right_global);
Expand Down Expand Up @@ -753,7 +884,7 @@ impl TexWrap {
}
}

pub fn get_dummy_texture_at_xy(&self, xa: i32, ya: i32) -> TextureResponse {
fn get_dummy_texture_at_xy(&self, xa: i32, ya: i32) -> TextureResponse {
let tex_width_int = self.width() as i32;
let tex_height_int = self.height() as i32;

Expand All @@ -766,14 +897,13 @@ impl TexWrap {
texture: &self.texture_boundary,
x_offset_texture: 0,
y_offset_texture: 0,
x_tex_left_global: xa,
y_tex_top_global: ya,
x_tex_right_global: xa + width - 1,
y_tex_bottom_global: ya + height - 1,
is_boundary: true,
}
}

pub fn get_texture_at_xy(&self, xa: i32, ya: i32) -> TextureResponse {
fn get_texture_at_xy(&self, xa: i32, ya: i32) -> TextureResponse {
let width_int = self.width() as i32;
let height_int = self.height() as i32;

Expand Down Expand Up @@ -807,16 +937,18 @@ impl TexWrap {
texture: my_tex_pair,
x_offset_texture: x_offset_texture,
y_offset_texture: y_offset_texture,
x_tex_left_global: tex_left,
y_tex_top_global: tex_top,
x_tex_right_global: tex_right,
y_tex_bottom_global: tex_bottom,
is_boundary: false,
}
}

fn add_draw_shader(&self, draw: &mut Draw) {
if let Some(pip) = &self.pipeline {
draw.image_pipeline().pipeline(pip);
draw.image_pipeline()
.pipeline(pip)
.uniform_buffer(&self.uniform_swizzle_mask)
.uniform_buffer(&self.uniform_offset_vec);
}
}

Expand Down
30 changes: 4 additions & 26 deletions src/ui/top_bar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,32 +104,10 @@ pub fn main_menu(ui: &mut Ui, state: &mut OculanteState, app: &mut App, gfx: &mu
});
});
}

// TODO: remove redundancy
if changed_channels {
// TODO: Make this dependent of DynamicImage's type
if let Some(img) = &state.current_image {
match &state.persistent_settings.current_channel {
ColorChannel::Rgb => {
state.current_texture.set_image(
&unpremult(img),
gfx,
&state.persistent_settings,
);
}
ColorChannel::Rgba => {
state
.current_texture
.set_image(img, gfx, &state.persistent_settings);
}
_ => {
let solo_im =
solo_channel(img, state.persistent_settings.current_channel as usize);
state
.current_texture
.set_image(&solo_im, gfx, &state.persistent_settings);
}
}

if changed_channels {
if state.current_image.is_some() {
state.current_texture.update_color_selection(gfx, &state.persistent_settings);
}
}

Expand Down
Loading