Wire live serial data into matrix renderer
This commit is contained in:
87
src/app.rs
87
src/app.rs
@@ -1,25 +1,29 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use eframe::{egui, egui_wgpu};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::connection::ConnectionManager;
|
||||
use crate::theme::{ENGINEERING_DARK, apply_fonts, apply_theme};
|
||||
use crate::{
|
||||
matrix::{MATRIX_COLS, MATRIX_ROWS},
|
||||
render::{BackgroundRenderResources, WgpuBackgroundCallback},
|
||||
render::{BackgroundRenderResources, PRESSURE_CELL_COUNT, WgpuBackgroundCallback},
|
||||
ui::{
|
||||
ConfigPanelState, ConnectPanelState, FloatingPanelState, draw_config_panel,
|
||||
draw_connect_panel, draw_scene_panel, draw_stats_panel,
|
||||
},
|
||||
};
|
||||
|
||||
const DATA_LOG_EVERY_FRAMES: u64 = 30;
|
||||
|
||||
pub struct EskinDesktopApp {
|
||||
connect_panel: FloatingPanelState,
|
||||
connect_state: ConnectPanelState,
|
||||
connection: Arc<ConnectionManager>,
|
||||
pressure_matrix: [f32; PRESSURE_CELL_COUNT],
|
||||
data_log_frame: u64,
|
||||
scene_panel: FloatingPanelState,
|
||||
config_panel: FloatingPanelState,
|
||||
config_state: ConfigPanelState,
|
||||
stats_panel: FloatingPanelState,
|
||||
started_at: Instant,
|
||||
}
|
||||
|
||||
impl EskinDesktopApp {
|
||||
@@ -46,15 +50,19 @@ impl EskinDesktopApp {
|
||||
Self {
|
||||
connect_panel: FloatingPanelState::new([0.0, 0.0], [0.0, 0.0]),
|
||||
connect_state: ConnectPanelState::default(),
|
||||
connection: Arc::new(ConnectionManager::new()),
|
||||
pressure_matrix: [0.0; PRESSURE_CELL_COUNT],
|
||||
data_log_frame: 0,
|
||||
scene_panel: FloatingPanelState::new([16.0, 48.0], [16.0, 48.0]),
|
||||
config_panel: FloatingPanelState::new([840.0, 48.0], [128.0, 48.0]),
|
||||
config_state: ConfigPanelState::default(),
|
||||
stats_panel: FloatingPanelState::new([16.0, 520.0], [240.0, 48.0]),
|
||||
started_at: Instant::now(),
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_wgpu_background(&mut self, ui: &mut egui::Ui) {
|
||||
self.update_pressure_matrix();
|
||||
|
||||
let rect = ui.max_rect();
|
||||
let width = rect.width().max(1.0);
|
||||
let height = rect.height().max(1.0);
|
||||
@@ -64,11 +72,26 @@ impl EskinDesktopApp {
|
||||
WgpuBackgroundCallback {
|
||||
width,
|
||||
height,
|
||||
time: self.started_at.elapsed().as_secs_f32(),
|
||||
pressure: self.pressure_matrix,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
fn update_pressure_matrix(&mut self) {
|
||||
if let Some(sample) = self.connection.take_latest_sample() {
|
||||
normalize_pressure_sample(
|
||||
&sample.matrix,
|
||||
sample.rows,
|
||||
sample.cols,
|
||||
&mut self.pressure_matrix,
|
||||
);
|
||||
self.data_log_frame += 1;
|
||||
if self.data_log_frame % DATA_LOG_EVERY_FRAMES == 0 {
|
||||
log_pressure_sample(&sample.matrix, sample.rows, sample.cols);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_toolbar(&mut self, ui: &mut egui::Ui) {
|
||||
egui::Panel::top("main_menu").show_inside(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
@@ -81,13 +104,63 @@ impl EskinDesktopApp {
|
||||
}
|
||||
|
||||
fn draw_floating_panels(&mut self, ctx: &egui::Context) {
|
||||
draw_connect_panel(ctx, &mut self.connect_panel, &mut self.connect_state);
|
||||
draw_connect_panel(
|
||||
ctx,
|
||||
&mut self.connect_panel,
|
||||
&mut self.connect_state,
|
||||
&self.connection,
|
||||
);
|
||||
draw_scene_panel(ctx, &mut self.scene_panel);
|
||||
draw_config_panel(ctx, &mut self.config_panel, &mut self.config_state);
|
||||
draw_stats_panel(ctx, &mut self.stats_panel);
|
||||
}
|
||||
}
|
||||
|
||||
fn log_pressure_sample(raw: &[u32], rows: u32, cols: u32) {
|
||||
let max = raw.iter().copied().max().unwrap_or(0);
|
||||
let sum: u64 = raw.iter().map(|value| *value as u64).sum();
|
||||
let non_zero = raw.iter().filter(|value| **value != 0).count();
|
||||
let preview = raw
|
||||
.iter()
|
||||
.take(12)
|
||||
.map(u32::to_string)
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
println!(
|
||||
"[pressure] {rows}x{cols} cells={} non_zero={non_zero} max={max} sum={sum} first=[{preview}]",
|
||||
raw.len()
|
||||
);
|
||||
}
|
||||
|
||||
fn normalize_pressure_sample(
|
||||
raw: &[u32],
|
||||
rows: u32,
|
||||
cols: u32,
|
||||
normalized: &mut [f32; PRESSURE_CELL_COUNT],
|
||||
) {
|
||||
normalized.fill(0.0);
|
||||
let max_value = raw.iter().copied().max().unwrap_or(0);
|
||||
|
||||
if max_value == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let src_cols = cols.max(1);
|
||||
let copy_rows = MATRIX_ROWS.min(rows);
|
||||
let copy_cols = MATRIX_COLS.min(cols);
|
||||
|
||||
for row in 0..copy_rows {
|
||||
for col in 0..copy_cols {
|
||||
let src_index = (row * src_cols + col) as usize;
|
||||
let dst_index = (row * MATRIX_COLS + col) as usize;
|
||||
if let Some(value) = raw.get(src_index) {
|
||||
normalized[dst_index] = (*value as f32 / max_value as f32).clamp(0.0, 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for EskinDesktopApp {
|
||||
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
|
||||
let ctx = ui.ctx().clone();
|
||||
|
||||
Reference in New Issue
Block a user