use std::collections::HashMap; use wgpu_glyph::{GlyphBrush, ab_glyph::FontArc, GlyphBrushBuilder, Section, Text}; use wgpu::util::StagingBelt; use futures::executor::LocalPool; use futures::task::SpawnExt; const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0]; //const BLUE: [f32; 4] = [0.0, 0.2, 1.0, 1.0]; const GREEN: [f32; 4] = [0.1, 1.0, 0.0, 1.0]; pub struct UserInterface { // Glyph drawing staging_belt: StagingBelt, local_pool: LocalPool, brush: GlyphBrush<()>, // Texts texts: HashMap> } impl UserInterface { pub fn new(device: &mut wgpu::Device, render_format: wgpu::TextureFormat) -> Self { let font = FontArc::try_from_slice(include_bytes!("../../assets/font.ttf")).unwrap(); Self { staging_belt: StagingBelt::new(1024), local_pool: LocalPool::new(), brush: GlyphBrushBuilder::using_font(font).build(device, render_format), texts: HashMap::new() } } fn print(brush: &mut GlyphBrush<()>, line: u32, text: &str, color: [f32; 4]) { let t = Text::new(text).with_color(color); brush.queue(Section { screen_position: (5 as f32, (5 + line*15) as f32), bounds: (t.scale.x * t.text.len() as f32, t.scale.y), text: vec![t], ..Section::default() }); } pub fn set_text(&mut self, cat: &str, line: usize, text: String) { // Category let c = &cat.to_string(); if !self.texts.contains_key(c) {self.texts.insert(c.clone(), Vec::new());} // Texts let v = self.texts.get_mut(c).unwrap(); while v.len() < line+1 { v.push(String::new()); } v[line] = text; } pub fn render(&mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, target: &wgpu::TextureView, width: u32, height: u32) { let mut line = 0; for (cat, texts) in self.texts.iter_mut() { UserInterface::print(&mut self.brush, line, cat, GREEN); line += 1; for text in texts.iter() { UserInterface::print(&mut self.brush, line, text, WHITE); line += 1; } line += 1; } // Draw self.brush.draw_queued(&device, &mut self.staging_belt, encoder, target, width, height).expect("Draw queued"); self.staging_belt.finish(); } pub fn recall(&mut self) { // Reset staging belt after drawing self.local_pool.spawner().spawn(self.staging_belt.recall()).expect("Recall staging belt"); self.local_pool.run_until_stalled(); } }