Save/load more config
This commit is contained in:
parent
6e2d70abd7
commit
e31269368d
|
@ -18,6 +18,16 @@ version = "0.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
|
checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "accesskit"
|
||||||
|
version = "0.16.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "99b76d84ee70e30a4a7e39ab9018e2b17a6a09e31084176cc7c0b2dec036ba45"
|
||||||
|
dependencies = [
|
||||||
|
"enumn",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "adler2"
|
name = "adler2"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
|
@ -33,6 +43,7 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"serde",
|
||||||
"version_check",
|
"version_check",
|
||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
@ -923,6 +934,7 @@ checksum = "775cfde491852059e386c4e1deb4aef381c617dc364184c6f6afee99b87c402b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"emath",
|
"emath",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -931,11 +943,13 @@ version = "0.29.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53eafabcce0cb2325a59a98736efe0bf060585b437763f8c476957fb274bb974"
|
checksum = "53eafabcce0cb2325a59a98736efe0bf060585b437763f8c476957fb274bb974"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"accesskit",
|
||||||
"ahash",
|
"ahash",
|
||||||
"emath",
|
"emath",
|
||||||
"epaint",
|
"epaint",
|
||||||
"log",
|
"log",
|
||||||
"nohash-hasher",
|
"nohash-hasher",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1009,6 +1023,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1fe0049ce51d0fb414d029e668dd72eb30bc2b739bf34296ed97bd33df544f3"
|
checksum = "b1fe0049ce51d0fb414d029e668dd72eb30bc2b739bf34296ed97bd33df544f3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1059,6 +1074,17 @@ dependencies = [
|
||||||
"syn 2.0.90",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enumn"
|
||||||
|
version = "0.1.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.90",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "epaint"
|
name = "epaint"
|
||||||
version = "0.29.1"
|
version = "0.29.1"
|
||||||
|
@ -1074,6 +1100,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"nohash-hasher",
|
"nohash-hasher",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -10,7 +10,7 @@ bytemuck = { version = "1", features = ["derive"] }
|
||||||
clap = { version = "4", features = ["derive"] }
|
clap = { version = "4", features = ["derive"] }
|
||||||
cpal = { git = "https://github.com/sidit77/cpal.git", rev = "66ed6be" }
|
cpal = { git = "https://github.com/sidit77/cpal.git", rev = "66ed6be" }
|
||||||
directories = "5"
|
directories = "5"
|
||||||
egui = "0.29"
|
egui = { version = "0.29", features = ["serde"] }
|
||||||
egui_extras = "0.29"
|
egui_extras = "0.29"
|
||||||
egui-toast = "0.15"
|
egui-toast = "0.15"
|
||||||
egui-winit = "0.29"
|
egui-winit = "0.29"
|
||||||
|
|
18
src/app.rs
18
src/app.rs
|
@ -38,6 +38,7 @@ pub struct Application {
|
||||||
proxy: EventLoopProxy<UserEvent>,
|
proxy: EventLoopProxy<UserEvent>,
|
||||||
mappings: MappingProvider,
|
mappings: MappingProvider,
|
||||||
controllers: ControllerManager,
|
controllers: ControllerManager,
|
||||||
|
persistence: Persistence,
|
||||||
viewports: HashMap<ViewportId, Viewport>,
|
viewports: HashMap<ViewportId, Viewport>,
|
||||||
focused: Option<ViewportId>,
|
focused: Option<ViewportId>,
|
||||||
}
|
}
|
||||||
|
@ -46,7 +47,7 @@ impl Application {
|
||||||
pub fn new(client: EmulatorClient, proxy: EventLoopProxy<UserEvent>) -> Self {
|
pub fn new(client: EmulatorClient, proxy: EventLoopProxy<UserEvent>) -> Self {
|
||||||
let icon = load_icon().ok().map(Arc::new);
|
let icon = load_icon().ok().map(Arc::new);
|
||||||
let persistence = Persistence::new();
|
let persistence = Persistence::new();
|
||||||
let mappings = MappingProvider::new(persistence);
|
let mappings = MappingProvider::new(persistence.clone());
|
||||||
let controllers = ControllerManager::new(client.clone(), &mappings);
|
let controllers = ControllerManager::new(client.clone(), &mappings);
|
||||||
{
|
{
|
||||||
let mappings = mappings.clone();
|
let mappings = mappings.clone();
|
||||||
|
@ -59,6 +60,7 @@ impl Application {
|
||||||
proxy,
|
proxy,
|
||||||
mappings,
|
mappings,
|
||||||
controllers,
|
controllers,
|
||||||
|
persistence,
|
||||||
viewports: HashMap::new(),
|
viewports: HashMap::new(),
|
||||||
focused: None,
|
focused: None,
|
||||||
}
|
}
|
||||||
|
@ -78,7 +80,12 @@ impl Application {
|
||||||
|
|
||||||
impl ApplicationHandler<UserEvent> for Application {
|
impl ApplicationHandler<UserEvent> for Application {
|
||||||
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
let app = GameWindow::new(self.client.clone(), self.proxy.clone(), SimId::Player1);
|
let app = GameWindow::new(
|
||||||
|
self.client.clone(),
|
||||||
|
self.proxy.clone(),
|
||||||
|
self.persistence.clone(),
|
||||||
|
SimId::Player1,
|
||||||
|
);
|
||||||
let wrapper = Viewport::new(event_loop, self.icon.clone(), Box::new(app));
|
let wrapper = Viewport::new(event_loop, self.icon.clone(), Box::new(app));
|
||||||
self.focused = Some(wrapper.id());
|
self.focused = Some(wrapper.id());
|
||||||
self.viewports.insert(wrapper.id(), wrapper);
|
self.viewports.insert(wrapper.id(), wrapper);
|
||||||
|
@ -177,7 +184,12 @@ impl ApplicationHandler<UserEvent> for Application {
|
||||||
self.open(event_loop, Box::new(input));
|
self.open(event_loop, Box::new(input));
|
||||||
}
|
}
|
||||||
UserEvent::OpenPlayer2 => {
|
UserEvent::OpenPlayer2 => {
|
||||||
let p2 = GameWindow::new(self.client.clone(), self.proxy.clone(), SimId::Player2);
|
let p2 = GameWindow::new(
|
||||||
|
self.client.clone(),
|
||||||
|
self.proxy.clone(),
|
||||||
|
self.persistence.clone(),
|
||||||
|
SimId::Player2,
|
||||||
|
);
|
||||||
self.open(event_loop, Box::new(p2));
|
self.open(event_loop, Box::new(p2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::sync::mpsc;
|
||||||
use crate::{
|
use crate::{
|
||||||
app::UserEvent,
|
app::UserEvent,
|
||||||
emulator::{EmulatorClient, EmulatorCommand, SimId},
|
emulator::{EmulatorClient, EmulatorCommand, SimId},
|
||||||
|
persistence::Persistence,
|
||||||
};
|
};
|
||||||
use egui::{
|
use egui::{
|
||||||
ecolor::HexColor, menu, Align2, Button, CentralPanel, Color32, Context, Direction, Frame,
|
ecolor::HexColor, menu, Align2, Button, CentralPanel, Color32, Context, Direction, Frame,
|
||||||
|
@ -10,6 +11,7 @@ use egui::{
|
||||||
ViewportId, WidgetText, Window,
|
ViewportId, WidgetText, Window,
|
||||||
};
|
};
|
||||||
use egui_toast::{Toast, Toasts};
|
use egui_toast::{Toast, Toasts};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use winit::event_loop::EventLoopProxy;
|
use winit::event_loop::EventLoopProxy;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -35,22 +37,28 @@ const COLOR_PRESETS: [[Color32; 2]; 3] = [
|
||||||
pub struct GameWindow {
|
pub struct GameWindow {
|
||||||
client: EmulatorClient,
|
client: EmulatorClient,
|
||||||
proxy: EventLoopProxy<UserEvent>,
|
proxy: EventLoopProxy<UserEvent>,
|
||||||
|
persistence: Persistence,
|
||||||
sim_id: SimId,
|
sim_id: SimId,
|
||||||
display_mode: DisplayMode,
|
config: GameConfig,
|
||||||
colors: [Color32; 2],
|
|
||||||
screen: Option<GameScreen>,
|
screen: Option<GameScreen>,
|
||||||
messages: Option<mpsc::Receiver<Toast>>,
|
messages: Option<mpsc::Receiver<Toast>>,
|
||||||
color_picker: Option<ColorPickerState>,
|
color_picker: Option<ColorPickerState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameWindow {
|
impl GameWindow {
|
||||||
pub fn new(client: EmulatorClient, proxy: EventLoopProxy<UserEvent>, sim_id: SimId) -> Self {
|
pub fn new(
|
||||||
|
client: EmulatorClient,
|
||||||
|
proxy: EventLoopProxy<UserEvent>,
|
||||||
|
persistence: Persistence,
|
||||||
|
sim_id: SimId,
|
||||||
|
) -> Self {
|
||||||
|
let config = load_config(&persistence, sim_id);
|
||||||
Self {
|
Self {
|
||||||
client,
|
client,
|
||||||
proxy,
|
proxy,
|
||||||
|
persistence,
|
||||||
sim_id,
|
sim_id,
|
||||||
display_mode: DisplayMode::Anaglyph,
|
config,
|
||||||
colors: COLOR_PRESETS[0],
|
|
||||||
screen: None,
|
screen: None,
|
||||||
messages: None,
|
messages: None,
|
||||||
color_picker: None,
|
color_picker: None,
|
||||||
|
@ -99,7 +107,7 @@ impl GameWindow {
|
||||||
let label = format!("x{scale}");
|
let label = format!("x{scale}");
|
||||||
let scale = scale as f32;
|
let scale = scale as f32;
|
||||||
let dims = {
|
let dims = {
|
||||||
let Vec2 { x, y } = self.display_mode.proportions();
|
let Vec2 { x, y } = self.config.display_mode.proportions();
|
||||||
Vec2::new(x * scale, y * scale + 22.0)
|
Vec2::new(x * scale, y * scale + 22.0)
|
||||||
};
|
};
|
||||||
if ui
|
if ui
|
||||||
|
@ -113,49 +121,46 @@ impl GameWindow {
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.menu_button("Display Mode", |ui| {
|
ui.menu_button("Display Mode", |ui| {
|
||||||
let old_proportions = self.display_mode.proportions();
|
let old_proportions = self.config.display_mode.proportions();
|
||||||
if ui
|
let mut changed = false;
|
||||||
.selectable_option(&mut self.display_mode, DisplayMode::Anaglyph, "Anaglyph")
|
let mut display_mode = self.config.display_mode;
|
||||||
.clicked()
|
changed |= ui
|
||||||
{
|
.selectable_option(&mut display_mode, DisplayMode::Anaglyph, "Anaglyph")
|
||||||
ui.close_menu();
|
.clicked();
|
||||||
}
|
changed |= ui
|
||||||
if ui
|
.selectable_option(&mut display_mode, DisplayMode::LeftEye, "Left Eye")
|
||||||
.selectable_option(&mut self.display_mode, DisplayMode::LeftEye, "Left Eye")
|
.clicked();
|
||||||
.clicked()
|
changed |= ui
|
||||||
{
|
.selectable_option(&mut display_mode, DisplayMode::RightEye, "Right Eye")
|
||||||
ui.close_menu();
|
.clicked();
|
||||||
}
|
changed |= ui
|
||||||
if ui
|
.selectable_option(&mut display_mode, DisplayMode::SideBySide, "Side by Side")
|
||||||
.selectable_option(&mut self.display_mode, DisplayMode::RightEye, "Right Eye")
|
.clicked();
|
||||||
.clicked()
|
|
||||||
{
|
if !changed {
|
||||||
ui.close_menu();
|
return;
|
||||||
}
|
|
||||||
if ui
|
|
||||||
.selectable_option(
|
|
||||||
&mut self.display_mode,
|
|
||||||
DisplayMode::SideBySide,
|
|
||||||
"Side by Side",
|
|
||||||
)
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
ui.close_menu();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_proportions = self.display_mode.proportions();
|
let current_dims = {
|
||||||
|
let viewport = ctx.input(|i| i.viewport().inner_rect.unwrap());
|
||||||
|
viewport.max - viewport.min
|
||||||
|
};
|
||||||
|
let new_proportions = display_mode.proportions();
|
||||||
let scale = new_proportions / old_proportions;
|
let scale = new_proportions / old_proportions;
|
||||||
if scale != Vec2::new(1.0, 1.0) {
|
if scale != Vec2::new(1.0, 1.0) {
|
||||||
let current_dims = ctx.input(|i| i.viewport().inner_rect.unwrap());
|
|
||||||
let current_dims = current_dims.max - current_dims.min;
|
|
||||||
|
|
||||||
ctx.send_viewport_cmd(ViewportCommand::InnerSize(current_dims * scale));
|
ctx.send_viewport_cmd(ViewportCommand::InnerSize(current_dims * scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.update_config(|c| {
|
||||||
|
c.display_mode = display_mode;
|
||||||
|
c.dimensions = current_dims * scale;
|
||||||
|
});
|
||||||
|
ui.close_menu();
|
||||||
});
|
});
|
||||||
ui.menu_button("Colors", |ui| {
|
ui.menu_button("Colors", |ui| {
|
||||||
for preset in COLOR_PRESETS {
|
for preset in COLOR_PRESETS {
|
||||||
if ui.color_pair_button(preset[0], preset[1]).clicked() {
|
if ui.color_pair_button(preset[0], preset[1]).clicked() {
|
||||||
self.colors = preset;
|
self.update_config(|c| c.colors = preset);
|
||||||
ui.close_menu();
|
ui.close_menu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,8 +173,12 @@ impl GameWindow {
|
||||||
if is_running {
|
if is_running {
|
||||||
self.client.send_command(EmulatorCommand::Pause);
|
self.client.send_command(EmulatorCommand::Pause);
|
||||||
}
|
}
|
||||||
|
let color_codes = [
|
||||||
|
color_str(self.config.colors[0]),
|
||||||
|
color_str(self.config.colors[1]),
|
||||||
|
];
|
||||||
self.color_picker = Some(ColorPickerState {
|
self.color_picker = Some(ColorPickerState {
|
||||||
color_codes: [color_str(self.colors[0]), color_str(self.colors[1])],
|
color_codes,
|
||||||
just_opened: true,
|
just_opened: true,
|
||||||
unpause_on_close: is_running,
|
unpause_on_close: is_running,
|
||||||
});
|
});
|
||||||
|
@ -223,18 +232,21 @@ impl GameWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_color_picker(&mut self, ui: &mut Ui) {
|
fn show_color_picker(&mut self, ui: &mut Ui) {
|
||||||
|
let mut colors = self.config.colors;
|
||||||
let Some(state) = self.color_picker.as_mut() else {
|
let Some(state) = self.color_picker.as_mut() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let open = ui
|
let (open, updated) = ui
|
||||||
.horizontal(|ui| {
|
.horizontal(|ui| {
|
||||||
let left_color = ui.color_picker(&mut self.colors[0], &mut state.color_codes[0]);
|
let left_color = ui.color_picker(&mut colors[0], &mut state.color_codes[0]);
|
||||||
if state.just_opened {
|
if state.just_opened {
|
||||||
left_color.request_focus();
|
left_color.request_focus();
|
||||||
state.just_opened = false;
|
state.just_opened = false;
|
||||||
}
|
}
|
||||||
let right_color = ui.color_picker(&mut self.colors[1], &mut state.color_codes[1]);
|
let right_color = ui.color_picker(&mut colors[1], &mut state.color_codes[1]);
|
||||||
left_color.has_focus() || right_color.has_focus()
|
let open = left_color.has_focus() || right_color.has_focus();
|
||||||
|
let updated = left_color.changed() || right_color.changed();
|
||||||
|
(open, updated)
|
||||||
})
|
})
|
||||||
.inner;
|
.inner;
|
||||||
if !open {
|
if !open {
|
||||||
|
@ -243,6 +255,38 @@ impl GameWindow {
|
||||||
}
|
}
|
||||||
self.color_picker = None;
|
self.color_picker = None;
|
||||||
}
|
}
|
||||||
|
if updated {
|
||||||
|
self.update_config(|c| c.colors = colors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_config(&mut self, update: impl FnOnce(&mut GameConfig)) {
|
||||||
|
let mut new_config = self.config.clone();
|
||||||
|
update(&mut new_config);
|
||||||
|
if self.config != new_config {
|
||||||
|
let _ = self
|
||||||
|
.persistence
|
||||||
|
.save_config(config_filename(self.sim_id), &new_config);
|
||||||
|
}
|
||||||
|
self.config = new_config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn config_filename(sim_id: SimId) -> &'static str {
|
||||||
|
match sim_id {
|
||||||
|
SimId::Player1 => "config_p1",
|
||||||
|
SimId::Player2 => "config_p2",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_config(persistence: &Persistence, sim_id: SimId) -> GameConfig {
|
||||||
|
if let Ok(config) = persistence.load_config(config_filename(sim_id)) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
GameConfig {
|
||||||
|
display_mode: DisplayMode::Anaglyph,
|
||||||
|
colors: COLOR_PRESETS[0],
|
||||||
|
dimensions: DisplayMode::Anaglyph.proportions() + Vec2::new(0.0, 22.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,13 +299,18 @@ impl AppWindow for GameWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initial_viewport(&self) -> ViewportBuilder {
|
fn initial_viewport(&self) -> ViewportBuilder {
|
||||||
let dimensions = self.display_mode.proportions() + Vec2::new(0.0, 22.0);
|
|
||||||
ViewportBuilder::default()
|
ViewportBuilder::default()
|
||||||
.with_title("Lemur")
|
.with_title("Lemur")
|
||||||
.with_inner_size(dimensions)
|
.with_inner_size(self.config.dimensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show(&mut self, ctx: &Context) {
|
fn show(&mut self, ctx: &Context) {
|
||||||
|
let dimensions = {
|
||||||
|
let bounds = ctx.input(|i| i.viewport().inner_rect.unwrap());
|
||||||
|
bounds.max - bounds.min
|
||||||
|
};
|
||||||
|
self.update_config(|c| c.dimensions = dimensions);
|
||||||
|
|
||||||
let mut toasts = Toasts::new()
|
let mut toasts = Toasts::new()
|
||||||
.anchor(Align2::LEFT_BOTTOM, (10.0, 10.0))
|
.anchor(Align2::LEFT_BOTTOM, (10.0, 10.0))
|
||||||
.direction(Direction::BottomUp);
|
.direction(Direction::BottomUp);
|
||||||
|
@ -289,7 +338,7 @@ impl AppWindow for GameWindow {
|
||||||
let frame = Frame::central_panel(&ctx.style()).fill(Color32::BLACK);
|
let frame = Frame::central_panel(&ctx.style()).fill(Color32::BLACK);
|
||||||
CentralPanel::default().frame(frame).show(ctx, |ui| {
|
CentralPanel::default().frame(frame).show(ctx, |ui| {
|
||||||
if let Some(screen) = self.screen.as_mut() {
|
if let Some(screen) = self.screen.as_mut() {
|
||||||
screen.update(self.display_mode, self.colors);
|
screen.update(self.config.display_mode, self.config.colors);
|
||||||
ui.add(screen);
|
ui.add(screen);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -383,3 +432,10 @@ struct ColorPickerState {
|
||||||
just_opened: bool,
|
just_opened: bool,
|
||||||
unpause_on_close: bool,
|
unpause_on_close: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
|
struct GameConfig {
|
||||||
|
display_mode: DisplayMode,
|
||||||
|
colors: [Color32; 2],
|
||||||
|
dimensions: Vec2,
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
use egui::{Color32, Rgba, Vec2, Widget};
|
use egui::{Color32, Rgba, Vec2, Widget};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use wgpu::{util::DeviceExt as _, BindGroup, BindGroupLayout, Buffer, RenderPipeline};
|
use wgpu::{util::DeviceExt as _, BindGroup, BindGroupLayout, Buffer, RenderPipeline};
|
||||||
|
|
||||||
use crate::graphics::TextureSink;
|
use crate::graphics::TextureSink;
|
||||||
|
@ -260,7 +261,7 @@ impl Colors {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
|
||||||
pub enum DisplayMode {
|
pub enum DisplayMode {
|
||||||
Anaglyph,
|
Anaglyph,
|
||||||
LeftEye,
|
LeftEye,
|
||||||
|
|
Loading…
Reference in New Issue