improved text rendering, slight refactor and enable dynamics
This commit is contained in:
parent
ebf1f35eaa
commit
e889aa9dc6
|
@ -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.
|
@ -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();
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
pub mod vertex;
|
||||
pub mod colors;
|
||||
pub mod time;
|
||||
pub mod scope;
|
||||
|
|
|
@ -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,
|
||||
}
|
|
@ -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")
|
||||
}
|
Loading…
Reference in New Issue