Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
5 changes: 4 additions & 1 deletion src-tauri/src/gpu_processing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,9 +382,12 @@ impl GpuProcessor {
cache: None,
});

// WGSL uniform layout may require a larger size than repr(C); round up to multiple of 16
// so the bound buffer size satisfies the shader (see "buffer bound with size X where shader expects Y").
let adjustments_size = std::mem::size_of::<AllAdjustments>() as u64;
let adjustments_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Adjustments Buffer"),
size: std::mem::size_of::<AllAdjustments>() as u64,
size: ((adjustments_size + 15) / 16) * 16,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
Expand Down
74 changes: 58 additions & 16 deletions src-tauri/src/image_processing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -992,10 +992,12 @@ pub struct GlobalAdjustments {
pub red_curve_count: u32,
pub green_curve_count: u32,
pub blue_curve_count: u32,
_pad_end1: f32,
_pad_end2: f32,
_pad_end3: f32,
_pad_end4: f32,
pub lab_curve_l: [Point; 16],
pub lab_curve_a: [Point; 16],
pub lab_curve_b: [Point; 16],
pub lab_curve_l_count: u32,
pub lab_curve_a_count: u32,
pub lab_curve_b_count: u32,

pub glow_amount: f32,
pub halation_amount: f32,
Expand Down Expand Up @@ -1051,10 +1053,13 @@ pub struct MaskAdjustments {
pub red_curve_count: u32,
pub green_curve_count: u32,
pub blue_curve_count: u32,
_pad_end4: f32,
_pad_end5: f32,
_pad_end6: f32,
_pad_end7: f32,
pub lab_curve_l: [Point; 16],
pub lab_curve_a: [Point; 16],
pub lab_curve_b: [Point; 16],
pub lab_curve_l_count: u32,
pub lab_curve_a_count: u32,
pub lab_curve_b_count: u32,
pub _pad_end: f32,
}

#[derive(Debug, Clone, Copy, Pod, Zeroable, Default)]
Expand All @@ -1066,6 +1071,7 @@ pub struct AllAdjustments {
pub tile_offset_x: u32,
pub tile_offset_y: u32,
pub mask_atlas_cols: u32,
pub _pad_tail: [[f32; 4]; 3],
}

struct AdjustmentScales {
Expand Down Expand Up @@ -1364,6 +1370,21 @@ fn get_global_adjustments_from_json(
} else {
Vec::new()
};
let lab_l_points: Vec<serde_json::Value> = if is_visible("curves") {
curves_obj["labL"].as_array().cloned().unwrap_or_default()
} else {
Vec::new()
};
let lab_a_points: Vec<serde_json::Value> = if is_visible("curves") {
curves_obj["labA"].as_array().cloned().unwrap_or_default()
} else {
Vec::new()
};
let lab_b_points: Vec<serde_json::Value> = if is_visible("curves") {
curves_obj["labB"].as_array().cloned().unwrap_or_default()
} else {
Vec::new()
};

let cg_obj = js_adjustments
.get("colorGrading")
Expand Down Expand Up @@ -1538,10 +1559,12 @@ fn get_global_adjustments_from_json(
red_curve_count: red_points.len() as u32,
green_curve_count: green_points.len() as u32,
blue_curve_count: blue_points.len() as u32,
_pad_end1: 0.0,
_pad_end2: 0.0,
_pad_end3: 0.0,
_pad_end4: 0.0,
lab_curve_l: convert_points_to_aligned(lab_l_points.clone()),
lab_curve_a: convert_points_to_aligned(lab_a_points.clone()),
lab_curve_b: convert_points_to_aligned(lab_b_points.clone()),
lab_curve_l_count: lab_l_points.len() as u32,
lab_curve_a_count: lab_a_points.len() as u32,
lab_curve_b_count: lab_b_points.len() as u32,

glow_amount: get_val("effects", "glowAmount", SCALES.glow, None),
halation_amount: get_val("effects", "halationAmount", SCALES.halation, None),
Expand Down Expand Up @@ -1593,6 +1616,21 @@ fn get_mask_adjustments_from_json(adj: &serde_json::Value) -> MaskAdjustments {
} else {
Vec::new()
};
let lab_l_points: Vec<serde_json::Value> = if is_visible("curves") {
curves_obj["labL"].as_array().cloned().unwrap_or_default()
} else {
Vec::new()
};
let lab_a_points: Vec<serde_json::Value> = if is_visible("curves") {
curves_obj["labA"].as_array().cloned().unwrap_or_default()
} else {
Vec::new()
};
let lab_b_points: Vec<serde_json::Value> = if is_visible("curves") {
curves_obj["labB"].as_array().cloned().unwrap_or_default()
} else {
Vec::new()
};
let cg_obj = adj.get("colorGrading").cloned().unwrap_or_default();

MaskAdjustments {
Expand Down Expand Up @@ -1670,10 +1708,13 @@ fn get_mask_adjustments_from_json(adj: &serde_json::Value) -> MaskAdjustments {
red_curve_count: red_points.len() as u32,
green_curve_count: green_points.len() as u32,
blue_curve_count: blue_points.len() as u32,
_pad_end4: 0.0,
_pad_end5: 0.0,
_pad_end6: 0.0,
_pad_end7: 0.0,
lab_curve_l: convert_points_to_aligned(lab_l_points.clone()),
lab_curve_a: convert_points_to_aligned(lab_a_points.clone()),
lab_curve_b: convert_points_to_aligned(lab_b_points.clone()),
lab_curve_l_count: lab_l_points.len() as u32,
lab_curve_a_count: lab_a_points.len() as u32,
lab_curve_b_count: lab_b_points.len() as u32,
_pad_end: 0.0,
}
}

Expand Down Expand Up @@ -1707,6 +1748,7 @@ pub fn get_all_adjustments_from_json(
tile_offset_x: 0,
tile_offset_y: 0,
mask_atlas_cols: 1,
_pad_tail: [[0.0; 4]; 3],
}
}

Expand Down
1 change: 1 addition & 0 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1562,6 +1562,7 @@ fn build_single_mask_adjustments(all: &AllAdjustments, mask_index: usize) -> All
tile_offset_x: all.tile_offset_x,
tile_offset_y: all.tile_offset_y,
mask_atlas_cols: all.mask_atlas_cols,
_pad_tail: [[0.0; 4]; 3],
};
single.mask_adjustments[0] = all.mask_adjustments[mask_index];
for i in 1..single.mask_adjustments.len() {
Expand Down
86 changes: 77 additions & 9 deletions src-tauri/src/shaders/shader.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,12 @@ struct GlobalAdjustments {
red_curve_count: u32,
green_curve_count: u32,
blue_curve_count: u32,
_pad_end1: f32,
_pad_end2: f32,
_pad_end3: f32,
_pad_end4: f32,
lab_curve_l: array<Point, 16>,
lab_curve_a: array<Point, 16>,
lab_curve_b: array<Point, 16>,
lab_curve_l_count: u32,
lab_curve_a_count: u32,
lab_curve_b_count: u32,

glow_amount: f32,
halation_amount: f32,
Expand Down Expand Up @@ -158,10 +160,13 @@ struct MaskAdjustments {
red_curve_count: u32,
green_curve_count: u32,
blue_curve_count: u32,
_pad_end4: f32,
_pad_end5: f32,
_pad_end6: f32,
_pad_end7: f32,
lab_curve_l: array<Point, 16>,
lab_curve_a: array<Point, 16>,
lab_curve_b: array<Point, 16>,
lab_curve_l_count: u32,
lab_curve_a_count: u32,
lab_curve_b_count: u32,
_pad_end: f32,
}

struct AllAdjustments {
Expand All @@ -171,6 +176,7 @@ struct AllAdjustments {
tile_offset_x: u32,
tile_offset_y: u32,
mask_atlas_cols: u32,
_pad_tail: array<vec4<f32>, 3>,
}

struct HslRange {
Expand Down Expand Up @@ -236,6 +242,47 @@ fn linear_to_srgb(c: vec3<f32>) -> vec3<f32> {
return select(higher, lower, c_clamped <= cutoff);
}

fn lab_f(t: f32) -> f32 {
return select(7.787 * t + 0.137931034, pow(max(t, 0.0), 0.33333334), t > 0.008856);
}

fn lab_inv_f(t: f32) -> f32 {
return select((t - 0.137931034) / 7.787, t * t * t, t > 0.20689655);
}

fn srgb_to_lab(c: vec3<f32>) -> vec3<f32> {
let lin = srgb_to_linear(c);
let x = lin.r * 0.4124564 + lin.g * 0.3575761 + lin.b * 0.1804375;
let y = lin.r * 0.2126729 + lin.g * 0.7151522 + lin.b * 0.0721750;
let z = lin.r * 0.0193339 + lin.g * 0.1191920 + lin.b * 0.9503041;
let xn = 0.95047;
let yn = 1.0;
let zn = 1.08883;
let fx = lab_f(x / xn);
let fy = lab_f(y / yn);
let fz = lab_f(z / zn);
let L = 116.0 * fy - 16.0;
let a = 500.0 * (fx - fy);
let b = 200.0 * (fy - fz);
return vec3<f32>(L, a, b);
}

fn lab_to_srgb(lab: vec3<f32>) -> vec3<f32> {
let xn = 0.95047;
let yn = 1.0;
let zn = 1.08883;
let fy = (lab.x + 16.0) / 116.0;
let fx = lab.y / 500.0 + fy;
let fz = fy - lab.z / 200.0;
let x = xn * lab_inv_f(fx);
let y = yn * lab_inv_f(fy);
let z = zn * lab_inv_f(fz);
let r = x * 3.2404542 + y * (-1.5371385) + z * (-0.4985314);
let g = x * (-0.9692660) + y * 1.8760108 + z * 0.0415560;
let b = x * 0.0556434 + y * (-0.2040259) + z * 1.0572252;
return linear_to_srgb(vec3<f32>(r, g, b));
}

fn rgb_to_hsv(c: vec3<f32>) -> vec3<f32> {
let c_max = max(c.r, max(c.g, c.b));
let c_min = min(c.r, min(c.g, c.b));
Expand Down Expand Up @@ -1025,6 +1072,24 @@ fn apply_all_curves(color: vec3<f32>, luma_curve: array<Point, 16>, luma_curve_c
}
}

fn apply_lab_curves(color: vec3<f32>, lab_curve_l: array<Point, 16>, lab_curve_l_count: u32, lab_curve_a: array<Point, 16>, lab_curve_a_count: u32, lab_curve_b: array<Point, 16>, lab_curve_b_count: u32) -> vec3<f32> {
let l_def = is_default_curve(lab_curve_l, lab_curve_l_count);
let a_def = is_default_curve(lab_curve_a, lab_curve_a_count);
let b_def = is_default_curve(lab_curve_b, lab_curve_b_count);
if (l_def && a_def && b_def) { return color; }
let lab = srgb_to_lab(color);
let L_in = clamp(lab.x, 0.0, 100.0);
let a_in = clamp(lab.y, -128.0, 127.0);
let b_in = clamp(lab.z, -128.0, 127.0);
let L_norm = L_in / 100.0;
let a_norm = (a_in + 128.0) / 256.0;
let b_norm = (b_in + 128.0) / 256.0;
let L_out = clamp(apply_curve(L_norm, lab_curve_l, lab_curve_l_count) * 100.0, 0.0, 100.0);
let a_out = clamp(apply_curve(a_norm, lab_curve_a, lab_curve_a_count) * 256.0 - 128.0, -128.0, 127.0);
let b_out = clamp(apply_curve(b_norm, lab_curve_b, lab_curve_b_count) * 256.0 - 128.0, -128.0, 127.0);
return lab_to_srgb(vec3<f32>(L_out, a_out, b_out));
}

fn apply_all_adjustments(
initial_rgb: vec3<f32>,
adj: GlobalAdjustments,
Expand Down Expand Up @@ -1462,15 +1527,18 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
adjustments.global.blue_curve, adjustments.global.blue_curve_count
);

final_rgb = apply_lab_curves(final_rgb, adjustments.global.lab_curve_l, adjustments.global.lab_curve_l_count, adjustments.global.lab_curve_a, adjustments.global.lab_curve_a_count, adjustments.global.lab_curve_b, adjustments.global.lab_curve_b_count);

for (var i = 0u; i < adjustments.mask_count; i = i + 1u) {
let influence = get_mask_influence(i, absolute_coord);
if (influence > 0.001) {
let mask_curved_srgb = apply_all_curves(final_rgb,
var mask_curved_srgb = apply_all_curves(final_rgb,
adjustments.mask_adjustments[i].luma_curve, adjustments.mask_adjustments[i].luma_curve_count,
adjustments.mask_adjustments[i].red_curve, adjustments.mask_adjustments[i].red_curve_count,
adjustments.mask_adjustments[i].green_curve, adjustments.mask_adjustments[i].green_curve_count,
adjustments.mask_adjustments[i].blue_curve, adjustments.mask_adjustments[i].blue_curve_count
);
mask_curved_srgb = apply_lab_curves(mask_curved_srgb, adjustments.mask_adjustments[i].lab_curve_l, adjustments.mask_adjustments[i].lab_curve_l_count, adjustments.mask_adjustments[i].lab_curve_a, adjustments.mask_adjustments[i].lab_curve_a_count, adjustments.mask_adjustments[i].lab_curve_b, adjustments.mask_adjustments[i].lab_curve_b_count);
final_rgb = mix(final_rgb, mask_curved_srgb, influence);
}
}
Expand Down
14 changes: 13 additions & 1 deletion src/components/adjustments/Curves.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export interface ChannelConfig {
[ActiveChannel.Red]: ColorData;
[ActiveChannel.Green]: ColorData;
[ActiveChannel.Blue]: ColorData;
[ActiveChannel.LabL]: ColorData;
[ActiveChannel.LabA]: ColorData;
[ActiveChannel.LabB]: ColorData;
}

interface ColorData {
Expand Down Expand Up @@ -284,6 +287,9 @@ export default function CurveGraph({
red: { color: '#FF6B6B', data: histogram?.red },
green: { color: '#6BCB77', data: histogram?.green },
blue: { color: '#4D96FF', data: histogram?.blue },
labL: { color: '#E8E8E8', data: histogram?.luma },
labA: { color: '#E86B6B', data: histogram?.red },
labB: { color: '#4D96FF', data: histogram?.blue },
};

const propPoints = adjustments?.curves?.[activeChannel];
Expand Down Expand Up @@ -434,6 +440,9 @@ export default function CurveGraph({
[ActiveChannel.Red]: defaultPoints,
[ActiveChannel.Green]: defaultPoints,
[ActiveChannel.Blue]: defaultPoints,
[ActiveChannel.LabL]: defaultPoints,
[ActiveChannel.LabA]: defaultPoints,
[ActiveChannel.LabB]: defaultPoints,
},
}));
};
Expand All @@ -442,7 +451,10 @@ export default function CurveGraph({
ActiveChannel.Luma,
ActiveChannel.Red,
ActiveChannel.Green,
ActiveChannel.Blue
ActiveChannel.Blue,
ActiveChannel.LabL,
ActiveChannel.LabA,
ActiveChannel.LabB,
].some(channel => {
if (channel === activeChannel) return false;
return !isDefaultCurve(adjustments.curves?.[channel]);
Expand Down
30 changes: 30 additions & 0 deletions src/utils/adjustments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { SubMask, SubMaskMode } from '../components/panel/right/Masks';
export enum ActiveChannel {
Blue = 'blue',
Green = 'green',
LabA = 'labA',
LabB = 'labB',
LabL = 'labL',
Luma = 'luma',
Red = 'red',
}
Expand Down Expand Up @@ -239,6 +242,9 @@ export interface Curves {
[index: string]: Array<Coord>;
blue: Array<Coord>;
green: Array<Coord>;
labA: Array<Coord>;
labB: Array<Coord>;
labL: Array<Coord>;
luma: Array<Coord>;
red: Array<Coord>;
}
Expand Down Expand Up @@ -360,6 +366,18 @@ export const INITIAL_MASK_ADJUSTMENTS: MaskAdjustments = {
{ x: 0, y: 0 },
{ x: 255, y: 255 },
],
labA: [
{ x: 0, y: 0 },
{ x: 255, y: 255 },
],
labB: [
{ x: 0, y: 0 },
{ x: 255, y: 255 },
],
labL: [
{ x: 0, y: 0 },
{ x: 255, y: 255 },
],
luma: [
{ x: 0, y: 0 },
{ x: 255, y: 255 },
Expand Down Expand Up @@ -435,6 +453,18 @@ export const INITIAL_ADJUSTMENTS: Adjustments = {
{ x: 0, y: 0 },
{ x: 255, y: 255 },
],
labA: [
{ x: 0, y: 0 },
{ x: 255, y: 255 },
],
labB: [
{ x: 0, y: 0 },
{ x: 255, y: 255 },
],
labL: [
{ x: 0, y: 0 },
{ x: 255, y: 255 },
],
luma: [
{ x: 0, y: 0 },
{ x: 255, y: 255 },
Expand Down
Loading