improved text rendering, slight refactor and enable dynamics

This commit is contained in:
core 2023-11-08 21:57:19 -05:00
parent ebf1f35eaa
commit e889aa9dc6
Signed by: core
GPG Key ID: FDBF740DADDCEECF
6 changed files with 109 additions and 80 deletions

View File

@ -1,6 +1,6 @@
use crate::loadar2;
use crate::mode::Mode;
use crate::scope::ScopeState;
use crate::rendering::scope::ScopeState;
pub fn should_newline(state: &mut ScopeState) -> bool {

Binary file not shown.

View File

@ -1,6 +1,5 @@
pub mod command;
pub mod mode;
pub mod scope;
pub mod sites;
pub mod utils;
pub mod vcp;
@ -9,7 +8,7 @@ pub mod rendering;
use crate::mode::Mode;
use crate::scope::{Preferences, ScopeState, WgpuState};
use crate::rendering::scope::{Preferences, ScopeState, WgpuState};
use log::{debug, error, info};
@ -71,39 +70,7 @@ pub async fn __nxrd_browser_init(w: u32, h: u32) -> AbiProxy {
canvas.set_width(w);
canvas.set_height(h);
let render_state = WgpuState::new(window, PhysicalSize::new(w, h)).await;
info!("initializing the scope");
let document = web_sys::window()
.expect("window should exist")
.document()
.expect("document should exist");
info!("finding form input element");
let file = document
.get_element_by_id("file")
.expect("file element should exist");
let file: web_sys::HtmlInputElement = file
.dyn_into::<web_sys::HtmlInputElement>()
.map_err(|_| ())
.expect("file input is not an input");
let mut scope_state = ScopeState {
ar2: None,
scope_mode: Mode::RadarInoperative,
file_input: file,
lat: 30.48500, // jacksonville
long: -81.70200, // jacksonville
prefs: Preferences { fcs: 20 },
command_buf: String::new(),
command_buf_response_mode: false,
new_data_available: false,
selected_elevation: 1,
show_ui: false,
wgpu: render_state,
};
let mut scope_state = ScopeState::new(window, PhysicalSize::new(w, h)).await;
let event_proxy: EventLoopProxy<RenderMessage> = event_loop.create_proxy();
@ -113,7 +80,6 @@ pub async fn __nxrd_browser_init(w: u32, h: u32) -> AbiProxy {
Event::UserEvent(e) => match e {
RenderMessage::Resize { new_w, new_h } => {
scope_state
.wgpu
.reconfigure(PhysicalSize::new(new_w, new_h));
}
},
@ -128,14 +94,14 @@ pub async fn __nxrd_browser_init(w: u32, h: u32) -> AbiProxy {
window.exit();
}
WindowEvent::Resized(physical_size) => {
scope_state.wgpu.reconfigure(*physical_size);
scope_state.reconfigure(*physical_size);
}
WindowEvent::RedrawRequested => {
scope_state.wgpu.update();
match scope_state.wgpu.render() {
scope_state.update();
match scope_state.render() {
Ok(_) => {}
Err(SurfaceError::Lost) => {
scope_state.wgpu.reconfigure(scope_state.wgpu.size)
scope_state.reconfigure(scope_state.wgpu.size)
}
Err(SurfaceError::OutOfMemory) => {
error!("out of memory!");
@ -147,7 +113,7 @@ pub async fn __nxrd_browser_init(w: u32, h: u32) -> AbiProxy {
_ => {}
},
Event::AboutToWait => {
scope_state.wgpu.window().request_redraw();
scope_state.window().request_redraw();
}
_ => {}
},

View File

@ -1,2 +1,4 @@
pub mod vertex;
pub mod colors;
pub mod time;
pub mod scope;

View File

@ -3,6 +3,9 @@ use nexrad2::Nexrad2Chunk;
use std::iter;
use chrono::Utc;
use log::info;
use wasm_bindgen::JsCast;
use web_sys::{HtmlInputElement};
@ -20,6 +23,7 @@ use winit::dpi::PhysicalSize;
use winit::event::WindowEvent;
use winit::window::Window;
use crate::rendering::colors::rgb_to_srgb;
use crate::rendering::time::zulu;
use crate::rendering::vertex::{VERTICES};
pub struct ScopeState {
@ -50,7 +54,7 @@ pub struct WgpuState {
pub glyph_brush: GlyphBrush<()>
}
impl WgpuState {
impl ScopeState {
pub async fn new(window: Window, size: PhysicalSize<u32>) -> Self {
let instance = Instance::new(InstanceDescriptor {
backends: Backends::all(),
@ -112,7 +116,7 @@ impl WgpuState {
let shader = device.create_shader_module(ShaderModuleDescriptor {
label: Some("Shader"),
source: ShaderSource::Wgsl(include_str!("./shader.wgsl").into()),
source: ShaderSource::Wgsl(include_str!("../shader.wgsl").into()),
});
let render_pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
@ -157,10 +161,10 @@ impl WgpuState {
});
let staging_belt = StagingBelt::new(1024);
let font = FontArc::try_from_slice(include_bytes!("./fonts/Hermit-Regular.otf")).unwrap();
let font = FontArc::try_from_slice(include_bytes!("../fonts/Inconsolata-Regular.ttf")).unwrap();
let mut glyph_brush = GlyphBrushBuilder::using_font(font).build(&device, surface_config.format);
Self {
let wgpu = WgpuState {
window,
surface,
device,
@ -171,19 +175,53 @@ impl WgpuState {
pipeline: render_pipeline,
staging_belt,
glyph_brush
}
};
info!("initializing the scope");
let document = web_sys::window()
.expect("window should exist")
.document()
.expect("document should exist");
info!("finding form input element");
let file = document
.get_element_by_id("file")
.expect("file element should exist");
let file: web_sys::HtmlInputElement = file
.dyn_into::<web_sys::HtmlInputElement>()
.map_err(|_| ())
.expect("file input is not an input");
let scope_state = ScopeState {
ar2: None,
scope_mode: Mode::RadarInoperative,
file_input: file,
lat: 30.48500, // jacksonville
long: -81.70200, // jacksonville
prefs: Preferences { fcs: 24.0 },
command_buf: String::new(),
command_buf_response_mode: false,
new_data_available: false,
selected_elevation: 1,
show_ui: false,
wgpu,
};
scope_state
}
pub fn window(&self) -> &Window {
&self.window
&self.wgpu.window
}
pub fn reconfigure(&mut self, new_size: PhysicalSize<u32>) {
if new_size.width > 0 && new_size.height > 0 {
self.size = new_size;
self.surface_config.width = new_size.width;
self.surface_config.height = new_size.height;
self.surface.configure(&self.device, &self.surface_config);
self.wgpu.size = new_size;
self.wgpu.surface_config.width = new_size.width;
self.wgpu.surface_config.height = new_size.height;
self.wgpu.surface.configure(&self.wgpu.device, &self.wgpu.surface_config);
}
}
@ -194,20 +232,19 @@ impl WgpuState {
pub fn update(&mut self) {}
pub fn render(&mut self) -> Result<(), SurfaceError> {
let output = self.surface.get_current_texture()?;
let output = self.wgpu.surface.get_current_texture()?;
let view = output
.texture
.create_view(&TextureViewDescriptor::default());
let mut encoder = self
.device
.wgpu.device
.create_command_encoder(&CommandEncoderDescriptor {
label: Some("Render Encoder"),
});
let physical_width = (self.surface_config.width as f64 * self.window.scale_factor()) as f32;
let physical_width = (self.wgpu.surface_config.width as f64 * self.wgpu.window.scale_factor()) as f32;
let physical_height =
(self.surface_config.height as f64 * self.window.scale_factor()) as f32;
(self.wgpu.surface_config.height as f64 * self.wgpu.window.scale_factor()) as f32;
// LOCK BLOCK
@ -232,59 +269,71 @@ impl WgpuState {
occlusion_query_set: None,
});
render_pass.set_pipeline(&self.pipeline);
render_pass.set_pipeline(&self.wgpu.pipeline);
render_pass.draw(0..3, 0..1);
}
self.glyph_brush.queue(Section {
screen_position: (10.0, 10.0),
bounds: (self.surface_config.width as f32, self.surface_config.height as f32),
text: vec![Text::new("NEXRAD INOP 00:00:00Z")
// TEXT RENDERING //
let time = Utc::now();
let line_height = self.prefs.fcs - 1.0;
self.wgpu.glyph_brush.queue(Section {
screen_position: (10.0, 8.0),
bounds: (self.wgpu.surface_config.width as f32, self.wgpu.surface_config.height as f32),
text: vec![Text::new(&format!(
"NEXRAD {} {}",
self
.ar2
.as_ref()
.map(|u| u.volume_header_record.icao.as_str())
.unwrap_or("INOP"),
zulu(time)
))
.with_color(rgb_to_srgb(0x32cd32, 1.0))
.with_scale(20.0)],
.with_scale(self.prefs.fcs)],
..Section::default()
});
self.glyph_brush.queue(Section {
screen_position: (10.0, 32.0),
bounds: (self.surface_config.width as f32, self.surface_config.height as f32),
self.wgpu.glyph_brush.queue(Section {
screen_position: (10.0, 8.0 + line_height),
bounds: (self.wgpu.surface_config.width as f32, self.wgpu.surface_config.height as f32),
text: vec![Text::new("RADAR INOPERATIVE NO DATA LOADED")
.with_color(rgb_to_srgb(0xff0000, 1.0))
.with_scale(26.0)],
.with_scale(self.prefs.fcs)],
..Section::default()
});
self.glyph_brush.queue(Section {
screen_position: (self.surface_config.width as f32 - 10.0, 10.0),
bounds: (self.surface_config.width as f32, self.surface_config.height as f32),
self.wgpu.glyph_brush.queue(Section {
screen_position: (self.wgpu.surface_config.width as f32 - 10.0, 8.0),
bounds: (self.wgpu.surface_config.width as f32, self.wgpu.surface_config.height as f32),
text: vec![Text::new("RADAR SITE")
.with_color(rgb_to_srgb(0x32cd32, 1.0))
.with_scale(12.0)],
.with_scale(self.prefs.fcs)],
..Section::default()
}.with_layout(Layout::default().h_align(HorizontalAlign::Right)));
self.glyph_brush
self.wgpu.glyph_brush
.draw_queued(
&self.device,
&mut self.staging_belt,
&self.wgpu.device,
&mut self.wgpu.staging_belt,
&mut encoder,
&view,
self.surface_config.width,
self.surface_config.height,
self.wgpu.surface_config.width,
self.wgpu.surface_config.height,
)
.expect("Draw queued");
self.staging_belt.finish();
self.queue.submit(iter::once(encoder.finish()));
self.wgpu.staging_belt.finish();
self.wgpu.queue.submit(iter::once(encoder.finish()));
output.present();
self.staging_belt.recall();
self.wgpu.staging_belt.recall();
Ok(())
}
}
pub struct Preferences {
pub fcs: usize,
pub fcs: f32,
}

View File

@ -0,0 +1,12 @@
use chrono::{DateTime, Timelike, Utc};
pub fn time(h: usize, m: usize, s: usize, tag_end: &str) -> String {
format!("{:0>2}:{:0>2}:{:0>2}{}", h, m, s, tag_end)
}
pub fn hms(t: DateTime<Utc>) -> (usize, usize, usize) {
(t.hour() as usize, t.minute() as usize, t.second() as usize)
}
pub fn zulu(t: DateTime<Utc>) -> String {
let t2 = hms(t);
time(t2.0, t2.1, t2.2, "Z")
}