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