Support choosing colors
This commit is contained in:
parent
4e42179ef3
commit
2e5d5e140f
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
emulator::{EmulatorClient, EmulatorCommand, SimId},
|
emulator::{EmulatorClient, EmulatorCommand, SimId},
|
||||||
};
|
};
|
||||||
use egui::{
|
use egui::{
|
||||||
menu, Button, CentralPanel, Color32, Context, Frame, Response, TopBottomPanel, Ui,
|
menu, Button, CentralPanel, Color32, Context, Frame, Response, Sense, TopBottomPanel, Ui, Vec2,
|
||||||
ViewportBuilder, ViewportCommand, ViewportId, WidgetText,
|
ViewportBuilder, ViewportCommand, ViewportId, WidgetText,
|
||||||
};
|
};
|
||||||
use winit::event_loop::EventLoopProxy;
|
use winit::event_loop::EventLoopProxy;
|
||||||
|
@ -13,11 +13,27 @@ use super::{
|
||||||
AppWindow,
|
AppWindow,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const COLOR_PRESETS: [[Color32; 2]; 3] = [
|
||||||
|
[
|
||||||
|
Color32::from_rgb(0xff, 0x00, 0x00),
|
||||||
|
Color32::from_rgb(0x00, 0xc6, 0xf0),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Color32::from_rgb(0x00, 0xb4, 0x00),
|
||||||
|
Color32::from_rgb(0xc8, 0x00, 0xff),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Color32::from_rgb(0xb4, 0x9b, 0x00),
|
||||||
|
Color32::from_rgb(0x00, 0x00, 0xff),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
pub struct GameWindow {
|
pub struct GameWindow {
|
||||||
client: EmulatorClient,
|
client: EmulatorClient,
|
||||||
proxy: EventLoopProxy<UserEvent>,
|
proxy: EventLoopProxy<UserEvent>,
|
||||||
sim_id: SimId,
|
sim_id: SimId,
|
||||||
display_mode: DisplayMode,
|
display_mode: DisplayMode,
|
||||||
|
colors: [Color32; 2],
|
||||||
screen: Option<GameScreen>,
|
screen: Option<GameScreen>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +44,7 @@ impl GameWindow {
|
||||||
proxy,
|
proxy,
|
||||||
sim_id,
|
sim_id,
|
||||||
display_mode: DisplayMode::Anaglyph,
|
display_mode: DisplayMode::Anaglyph,
|
||||||
|
colors: COLOR_PRESETS[0],
|
||||||
screen: None,
|
screen: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,6 +121,13 @@ impl GameWindow {
|
||||||
ui.close_menu();
|
ui.close_menu();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
ui.menu_button("Colors", |ui| {
|
||||||
|
for preset in COLOR_PRESETS {
|
||||||
|
if ui.color_pair_button(preset[0], preset[1]).clicked() {
|
||||||
|
self.colors = preset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
ui.menu_button("Audio", |ui| {
|
ui.menu_button("Audio", |ui| {
|
||||||
let p1_enabled = self.client.is_audio_enabled(SimId::Player1);
|
let p1_enabled = self.client.is_audio_enabled(SimId::Player1);
|
||||||
|
@ -175,7 +199,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.display_mode = self.display_mode;
|
screen.update(self.display_mode, self.colors);
|
||||||
ui.add(screen);
|
ui.add(screen);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -209,6 +233,8 @@ trait UiExt {
|
||||||
}
|
}
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn color_pair_button(&mut self, left: Color32, right: Color32) -> Response;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UiExt for Ui {
|
impl UiExt for Ui {
|
||||||
|
@ -219,4 +245,18 @@ impl UiExt for Ui {
|
||||||
let mut selected = selected;
|
let mut selected = selected;
|
||||||
self.checkbox(&mut selected, text)
|
self.checkbox(&mut selected, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn color_pair_button(&mut self, left: Color32, right: Color32) -> Response {
|
||||||
|
let button_size = Vec2::new(60.0, 20.0);
|
||||||
|
let (rect, response) = self.allocate_at_least(button_size, Sense::click());
|
||||||
|
let center_x = rect.center().x;
|
||||||
|
let left_rect = rect.with_max_x(center_x);
|
||||||
|
self.painter().rect_filled(left_rect, 0.0, left);
|
||||||
|
let right_rect = rect.with_min_x(center_x);
|
||||||
|
self.painter().rect_filled(right_rect, 0.0, right);
|
||||||
|
|
||||||
|
let style = self.style().interact(&response);
|
||||||
|
self.painter().rect_stroke(rect, 0.0, style.fg_stroke);
|
||||||
|
response
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
use egui::Widget;
|
use egui::{Color32, Rgba, Widget};
|
||||||
use wgpu::{util::DeviceExt as _, BindGroup, BindGroupLayout, RenderPipeline};
|
use wgpu::{util::DeviceExt as _, BindGroup, BindGroupLayout, Buffer, RenderPipeline};
|
||||||
|
|
||||||
use crate::graphics::TextureSink;
|
use crate::graphics::TextureSink;
|
||||||
|
|
||||||
pub struct GameScreen {
|
pub struct GameScreen {
|
||||||
bind_group: Arc<BindGroup>,
|
bind_group: Arc<BindGroup>,
|
||||||
pub display_mode: DisplayMode,
|
color_buffer: Arc<Buffer>,
|
||||||
|
display_mode: DisplayMode,
|
||||||
|
colors: Colors,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameScreen {
|
impl GameScreen {
|
||||||
|
@ -117,12 +119,12 @@ impl GameScreen {
|
||||||
|
|
||||||
let (sink, texture_view) = TextureSink::new(device, queue.clone());
|
let (sink, texture_view) = TextureSink::new(device, queue.clone());
|
||||||
let sampler = device.create_sampler(&wgpu::SamplerDescriptor::default());
|
let sampler = device.create_sampler(&wgpu::SamplerDescriptor::default());
|
||||||
let colors = Colors {
|
let colors = Colors::new(
|
||||||
left: [1.0, 0.0, 0.0, 1.0],
|
Color32::from_rgb(0xff, 0x00, 0x00),
|
||||||
right: [0.0, 0.7734375, 0.9375, 1.0],
|
Color32::from_rgb(0x00, 0xc6, 0xf0),
|
||||||
};
|
);
|
||||||
|
|
||||||
let color_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let color_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
label: Some("colors"),
|
label: Some("colors"),
|
||||||
contents: bytemuck::bytes_of(&colors),
|
contents: bytemuck::bytes_of(&colors),
|
||||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||||
|
@ -145,7 +147,7 @@ impl GameScreen {
|
||||||
},
|
},
|
||||||
wgpu::BindGroupEntry {
|
wgpu::BindGroupEntry {
|
||||||
binding: 2,
|
binding: 2,
|
||||||
resource: color_buf.as_entire_binding(),
|
resource: color_buffer.as_entire_binding(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -153,11 +155,18 @@ impl GameScreen {
|
||||||
(
|
(
|
||||||
Self {
|
Self {
|
||||||
bind_group: Arc::new(bind_group),
|
bind_group: Arc::new(bind_group),
|
||||||
|
color_buffer: Arc::new(color_buffer),
|
||||||
display_mode: DisplayMode::Anaglyph,
|
display_mode: DisplayMode::Anaglyph,
|
||||||
|
colors,
|
||||||
},
|
},
|
||||||
sink,
|
sink,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self, display_mode: DisplayMode, colors: [Color32; 2]) {
|
||||||
|
self.display_mode = display_mode;
|
||||||
|
self.colors = Colors::new(colors[0], colors[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for &mut GameScreen {
|
impl Widget for &mut GameScreen {
|
||||||
|
@ -167,7 +176,9 @@ impl Widget for &mut GameScreen {
|
||||||
response.rect,
|
response.rect,
|
||||||
GameScreenCallback {
|
GameScreenCallback {
|
||||||
bind_group: self.bind_group.clone(),
|
bind_group: self.bind_group.clone(),
|
||||||
|
color_buffer: self.color_buffer.clone(),
|
||||||
display_mode: self.display_mode,
|
display_mode: self.display_mode,
|
||||||
|
colors: self.colors,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
ui.painter().add(callback);
|
ui.painter().add(callback);
|
||||||
|
@ -177,10 +188,23 @@ impl Widget for &mut GameScreen {
|
||||||
|
|
||||||
struct GameScreenCallback {
|
struct GameScreenCallback {
|
||||||
bind_group: Arc<BindGroup>,
|
bind_group: Arc<BindGroup>,
|
||||||
|
color_buffer: Arc<Buffer>,
|
||||||
display_mode: DisplayMode,
|
display_mode: DisplayMode,
|
||||||
|
colors: Colors,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl egui_wgpu::CallbackTrait for GameScreenCallback {
|
impl egui_wgpu::CallbackTrait for GameScreenCallback {
|
||||||
|
fn prepare(
|
||||||
|
&self,
|
||||||
|
_device: &wgpu::Device,
|
||||||
|
queue: &wgpu::Queue,
|
||||||
|
_screen_descriptor: &egui_wgpu::ScreenDescriptor,
|
||||||
|
_egui_encoder: &mut wgpu::CommandEncoder,
|
||||||
|
_callback_resources: &mut egui_wgpu::CallbackResources,
|
||||||
|
) -> Vec<wgpu::CommandBuffer> {
|
||||||
|
queue.write_buffer(&self.color_buffer, 0, bytemuck::bytes_of(&self.colors));
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
fn paint(
|
fn paint(
|
||||||
&self,
|
&self,
|
||||||
info: egui::PaintCallbackInfo,
|
info: egui::PaintCallbackInfo,
|
||||||
|
@ -217,8 +241,16 @@ struct SharedGameScreenResources {
|
||||||
#[derive(Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
|
#[derive(Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct Colors {
|
struct Colors {
|
||||||
left: [f32; 4],
|
left: Rgba,
|
||||||
right: [f32; 4],
|
right: Rgba,
|
||||||
|
}
|
||||||
|
impl Colors {
|
||||||
|
fn new(left: Color32, right: Color32) -> Self {
|
||||||
|
Self {
|
||||||
|
left: left.into(),
|
||||||
|
right: right.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
|
|
Loading…
Reference in New Issue