mirror of https://github.com/wayvr-org/wayvr.git
dash-frontend: Chroma key settings
This commit is contained in:
parent
0c1b0906c1
commit
26f5be36b6
|
|
@ -1,12 +1,56 @@
|
|||
<layout>
|
||||
<include src="../t_group_box.xml" />
|
||||
|
||||
<elements>
|
||||
<rectangle macro="group_box">
|
||||
<GroupBoxTitle src_builtin="dashboard/settings.svg" translation="GENERAL_SETTINGS" />
|
||||
<macro name="slider" width="100%" height="24"/>
|
||||
|
||||
<label translation="DISPLAY_BRIGHTNESS" />
|
||||
<Slider id="slider_brightness" width="300" height="24" min_value="0" max_value="140" />
|
||||
</rectangle>
|
||||
<theme>
|
||||
<var key="s_width" value="500"/>
|
||||
</theme>
|
||||
|
||||
<elements>
|
||||
<div flex_direction="column" gap="8">
|
||||
<rectangle macro="group_box">
|
||||
<GroupBoxTitle src_builtin="dashboard/settings.svg" translation="GENERAL_SETTINGS" />
|
||||
|
||||
<label translation="DISPLAY_BRIGHTNESS" />
|
||||
<Slider id="slider_brightness" width="300" height="24" min_value="0" max_value="140" />
|
||||
</rectangle>
|
||||
<rectangle macro="group_box">
|
||||
<GroupBoxTitle src_builtin="dashboard/settings.svg" translation="APP_SETTINGS.COLOR_KEYING" />
|
||||
<div gap="8" width="~s_width">
|
||||
<div gap="8" flex_direction="column" width="100%">
|
||||
<label text="Color"/>
|
||||
<ColorSelector id="cs_keying" height="24" width="100%"/>
|
||||
</div>
|
||||
|
||||
<div gap="8" flex_direction="column" width="100%">
|
||||
<label text="Despill"/>
|
||||
<Slider id="slider_keying_despill" min_value="0" max_value="100" macro="slider"/>
|
||||
</div>
|
||||
|
||||
<div gap="8" flex_direction="column" width="100%">
|
||||
<label text="Curve"/>
|
||||
<Slider id="slider_keying_curve" min_value="0" max_value="100" macro="slider"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div gap="8" width="~s_width">
|
||||
<div gap="8" flex_direction="column" width="100%">
|
||||
<label text="Hue range"/>
|
||||
<Slider id="slider_keying_hue_range" min_value="0" max_value="100" macro="slider"/>
|
||||
</div>
|
||||
|
||||
<div gap="8" flex_direction="column" width="100%">
|
||||
<label text="Saturation range"/>
|
||||
<Slider id="slider_keying_saturation_range" min_value="0" max_value="100" macro="slider"/>
|
||||
</div>
|
||||
|
||||
<div gap="8" flex_direction="column" width="100%">
|
||||
<label text="Value range"/>
|
||||
<Slider id="slider_keying_value_range" min_value="0" max_value="100" macro="slider"/>
|
||||
</div>
|
||||
</div>
|
||||
</rectangle>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
</layout>
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Blocks the game from receiving poses when the keyboard is hovered and 'Block game input' is enabled",
|
||||
"CAPTURE_METHOD": "Wayland screen capture",
|
||||
"CAPTURE_METHOD_HELP": "Try changing this if you are\nexperiencing black or glitchy screens",
|
||||
"COLOR_KEYING": "Color keying",
|
||||
"CLEAR_PIPEWIRE_TOKENS": "Clear PipeWire tokens",
|
||||
"CLEAR_PIPEWIRE_TOKENS_HELP": "Prompt for screen selection on next start",
|
||||
"CLEAR_SAVED_STATE": "Clear saved state",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ use wgui::{
|
|||
bar_graph::{ComponentBarGraph, ValueCell},
|
||||
button::ComponentButton,
|
||||
checkbox::ComponentCheckbox,
|
||||
slider::ComponentSlider,
|
||||
color_selector::{ColorSelectorChangedCallback, ComponentColorSelector},
|
||||
slider::{ComponentSlider, SliderValueChangedCallback},
|
||||
tabs::ComponentTabs,
|
||||
},
|
||||
drawing::Color,
|
||||
|
|
@ -15,7 +16,10 @@ use wgui::{
|
|||
parser::{self, Fetchable, ParseDocumentParams, ParserState},
|
||||
task::Tasks,
|
||||
};
|
||||
use wlx_common::dash_interface::{self, MonadoDumpSessionFrame};
|
||||
use wlx_common::{
|
||||
config::GeneralConfig,
|
||||
dash_interface::{self, MonadoDumpSessionFrame},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
frontend::Frontend,
|
||||
|
|
@ -40,6 +44,7 @@ impl TabNameEnum {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Task {
|
||||
SetBrightness(f32),
|
||||
SetTab(TabNameEnum),
|
||||
|
|
@ -51,6 +56,8 @@ enum Task {
|
|||
// `DebugTimings` tab
|
||||
DebugTimingsRefreshSessionList,
|
||||
DebugTimingsSetSessionId(i64),
|
||||
|
||||
GeneralSettingsChromaUpdate,
|
||||
}
|
||||
|
||||
struct SubtabProcessList {
|
||||
|
|
@ -62,6 +69,13 @@ struct SubtabProcessList {
|
|||
struct SubtabGeneralSettings {
|
||||
#[allow(dead_code)]
|
||||
state: ParserState,
|
||||
|
||||
slider_keying_curve: Rc<ComponentSlider>,
|
||||
slider_keying_despill: Rc<ComponentSlider>,
|
||||
slider_keying_hue_range: Rc<ComponentSlider>,
|
||||
slider_keying_saturation_range: Rc<ComponentSlider>,
|
||||
slider_keying_value_range: Rc<ComponentSlider>,
|
||||
cs_keying: Rc<ComponentColorSelector>,
|
||||
}
|
||||
|
||||
struct DebugGraph {
|
||||
|
|
@ -158,6 +172,12 @@ impl<T> Tab<T> for TabMonado<T> {
|
|||
tab.set_session_id(&mut frontend.layout, session_id)?;
|
||||
}
|
||||
}
|
||||
Task::GeneralSettingsChromaUpdate => {
|
||||
if let Subtab::GeneralSettings(tab) = &mut self.subtab {
|
||||
tab.chroma_update(frontend.interface.general_config(data));
|
||||
frontend.interface.config_changed(data);
|
||||
}
|
||||
}
|
||||
Task::SetBrightness(brightness) => self.set_brightness(frontend, data, brightness),
|
||||
Task::SetTab(tab) => {
|
||||
frontend.layout.remove_children(self.id_content);
|
||||
|
|
@ -243,6 +263,8 @@ fn yesno(n: bool) -> &'static str {
|
|||
}
|
||||
}
|
||||
|
||||
const SLIDER_MULTIPLIER: f32 = 100.0;
|
||||
|
||||
impl SubtabGeneralSettings {
|
||||
fn new<T>(
|
||||
parent_id: WidgetID,
|
||||
|
|
@ -271,7 +293,84 @@ impl SubtabGeneralSettings {
|
|||
});
|
||||
}
|
||||
|
||||
Ok(Self { state })
|
||||
let config = frontend.interface.general_config(data);
|
||||
|
||||
let cs_keying = state.fetch_component_as::<ComponentColorSelector>("cs_keying")?;
|
||||
let slider_keying_despill = state.fetch_component_as::<ComponentSlider>("slider_keying_despill")?;
|
||||
let slider_keying_curve = state.fetch_component_as::<ComponentSlider>("slider_keying_curve")?;
|
||||
let slider_keying_hue_range = state.fetch_component_as::<ComponentSlider>("slider_keying_hue_range")?;
|
||||
let slider_keying_saturation_range =
|
||||
state.fetch_component_as::<ComponentSlider>("slider_keying_saturation_range")?;
|
||||
let slider_keying_value_range = state.fetch_component_as::<ComponentSlider>("slider_keying_value_range")?;
|
||||
|
||||
{
|
||||
let mut lc = frontend.layout.start_common();
|
||||
let mut common = lc.common();
|
||||
|
||||
// set initial values
|
||||
let (rgb, range_h, range_s, range_v) = config.chroma_key_params.get_rgb_and_hsv_ranges();
|
||||
slider_keying_curve.set_value(&mut common, config.chroma_key_params.curve * SLIDER_MULTIPLIER);
|
||||
slider_keying_despill.set_value(&mut common, config.chroma_key_params.despill * SLIDER_MULTIPLIER);
|
||||
slider_keying_hue_range.set_value(&mut common, range_h * SLIDER_MULTIPLIER);
|
||||
slider_keying_saturation_range.set_value(&mut common, range_s * SLIDER_MULTIPLIER);
|
||||
slider_keying_value_range.set_value(&mut common, range_v * SLIDER_MULTIPLIER);
|
||||
cs_keying.set_color(&mut common, rgb);
|
||||
|
||||
// prepare callbacks
|
||||
fn get_slider_callback(tasks: &Tasks<Task>) -> SliderValueChangedCallback {
|
||||
Box::new({
|
||||
let tasks = tasks.clone();
|
||||
move |_, _| {
|
||||
tasks.push(Task::GeneralSettingsChromaUpdate);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn get_color_selector_callback(tasks: &Tasks<Task>) -> ColorSelectorChangedCallback {
|
||||
Box::new({
|
||||
let tasks = tasks.clone();
|
||||
move |_, _| {
|
||||
tasks.push(Task::GeneralSettingsChromaUpdate);
|
||||
}
|
||||
})
|
||||
}
|
||||
slider_keying_curve.on_value_changed(get_slider_callback(&tasks));
|
||||
slider_keying_despill.on_value_changed(get_slider_callback(&tasks));
|
||||
slider_keying_hue_range.on_value_changed(get_slider_callback(&tasks));
|
||||
slider_keying_saturation_range.on_value_changed(get_slider_callback(&tasks));
|
||||
slider_keying_value_range.on_value_changed(get_slider_callback(&tasks));
|
||||
cs_keying.on_changed(get_color_selector_callback(&tasks));
|
||||
|
||||
lc.finish()?;
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
state,
|
||||
slider_keying_curve,
|
||||
slider_keying_despill,
|
||||
slider_keying_hue_range,
|
||||
slider_keying_saturation_range,
|
||||
slider_keying_value_range,
|
||||
cs_keying,
|
||||
})
|
||||
}
|
||||
|
||||
fn chroma_update(&mut self, config: &mut GeneralConfig) {
|
||||
let val_curve = self.slider_keying_curve.get_value();
|
||||
let val_despill = self.slider_keying_despill.get_value();
|
||||
let val_range_h = self.slider_keying_hue_range.get_value();
|
||||
let val_range_s = self.slider_keying_saturation_range.get_value();
|
||||
let val_range_v = self.slider_keying_value_range.get_value();
|
||||
let val_rgb = self.cs_keying.get_color();
|
||||
|
||||
config.chroma_key_params.despill = val_despill / SLIDER_MULTIPLIER;
|
||||
config.chroma_key_params.curve = val_curve / SLIDER_MULTIPLIER;
|
||||
config.chroma_key_params.update_hsv_range_from_rgb(
|
||||
val_rgb,
|
||||
val_range_h / SLIDER_MULTIPLIER,
|
||||
val_range_s / SLIDER_MULTIPLIER,
|
||||
val_range_v / SLIDER_MULTIPLIER,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -211,6 +211,32 @@ impl HsvColor {
|
|||
pub const fn new(h: f32, s: f32, v: f32, a: f32) -> Self {
|
||||
Self { h, s, v, a }
|
||||
}
|
||||
|
||||
pub fn to_rgb(&self) -> Color {
|
||||
if self.s == 0.0 {
|
||||
// gray
|
||||
return Color::new(self.v, self.v, self.v, 1.0);
|
||||
}
|
||||
|
||||
let h6 = self.h * 6.0;
|
||||
let i = h6.floor();
|
||||
let f = h6 - i;
|
||||
|
||||
let p = self.v * (1.0 - self.s);
|
||||
let q = self.v * (1.0 - self.s * f);
|
||||
let t = self.v * (1.0 - self.s * (1.0 - f));
|
||||
|
||||
let (r, g, b) = match i as i32 % 6 {
|
||||
0 => (self.v, t, p),
|
||||
1 => (q, self.v, p),
|
||||
2 => (p, self.v, t),
|
||||
3 => (p, q, self.v),
|
||||
4 => (t, p, self.v),
|
||||
_ => (self.v, p, q),
|
||||
};
|
||||
|
||||
Color::new(r, g, b, 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Color> for HsvColor {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use idmap::IdMap;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use strum::{AsRefStr, EnumProperty, EnumString, VariantArray};
|
||||
use wayvr_ipc::packet_client::WvrProcessLaunchParams;
|
||||
use wgui::drawing::{self, HsvColor};
|
||||
|
||||
use crate::{
|
||||
astr_containers::{AStrMap, AStrSet},
|
||||
|
|
@ -66,7 +67,7 @@ pub enum HandsfreePointer {
|
|||
EyeTrackingOnly,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Default)]
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct ChromaKeyParams {
|
||||
pub hsv_min: [f32; 3],
|
||||
pub hsv_max: [f32; 3],
|
||||
|
|
@ -74,6 +75,49 @@ pub struct ChromaKeyParams {
|
|||
pub despill: f32,
|
||||
}
|
||||
|
||||
fn hsv_green() -> [f32; 3] {
|
||||
[2.0 / 6.0, 1.0, 1.0]
|
||||
}
|
||||
|
||||
impl Default for ChromaKeyParams {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
hsv_min: hsv_green(),
|
||||
hsv_max: hsv_green(),
|
||||
curve: 0.0, // Monado will ignore chroma keying completely if this value is zero
|
||||
despill: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ChromaKeyParams {
|
||||
pub fn update_hsv_range_from_rgb(&mut self, rgb_color: drawing::Color, range_h: f32, range_s: f32, range_v: f32) {
|
||||
let hsv = HsvColor::from(rgb_color);
|
||||
self.hsv_min[0] = hsv.h - range_h / 2.0;
|
||||
self.hsv_min[1] = hsv.s - range_s / 2.0;
|
||||
self.hsv_min[2] = hsv.v - range_v / 2.0;
|
||||
self.hsv_max[0] = hsv.h + range_h / 2.0;
|
||||
self.hsv_max[1] = hsv.s + range_s / 2.0;
|
||||
self.hsv_max[2] = hsv.v + range_v / 2.0;
|
||||
}
|
||||
|
||||
// Inverse of `update_hsv_range_from_rgb` function
|
||||
pub fn get_rgb_and_hsv_ranges(&self) -> (drawing::Color, f32, f32, f32) {
|
||||
(
|
||||
HsvColor::new(
|
||||
(self.hsv_min[0] + self.hsv_max[0]) / 2.0,
|
||||
(self.hsv_min[1] + self.hsv_max[1]) / 2.0,
|
||||
(self.hsv_min[2] + self.hsv_max[2]) / 2.0,
|
||||
1.0,
|
||||
)
|
||||
.to_rgb(),
|
||||
self.hsv_max[0] - self.hsv_min[0],
|
||||
self.hsv_max[1] - self.hsv_min[1],
|
||||
self.hsv_max[2] - self.hsv_min[2],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct SerializedWindowSet {
|
||||
pub name: Arc<str>,
|
||||
|
|
|
|||
Loading…
Reference in New Issue