Parameterize the Renderer trait over GenericSim to avoid taking it dynamically
Notably, this allows the SerializerRenderer to serialize the actual state to disk, as-is. That'll allow for more compact images, and potentially also a way to resume simulations. I expect the viewer will be broken for new simulations, initially.
This commit is contained in:
103
src/render.rs
103
src/render.rs
@@ -59,7 +59,7 @@ fn scale_vector(x: Vec2, typical_mag: Flt) -> Vec2 {
|
||||
x.with_mag(new_mag)
|
||||
}
|
||||
|
||||
fn im_size(state: &dyn GenericSim, max_w: u32, max_h: u32) -> (u32, u32) {
|
||||
fn im_size<S: GenericSim>(state: &S, max_w: u32, max_h: u32) -> (u32, u32) {
|
||||
let mut width = max_w;
|
||||
let mut height = width * state.height() / state.width();
|
||||
if height > max_h {
|
||||
@@ -70,21 +70,21 @@ fn im_size(state: &dyn GenericSim, max_w: u32, max_h: u32) -> (u32, u32) {
|
||||
(width, height)
|
||||
}
|
||||
|
||||
struct RenderSteps<'a> {
|
||||
struct RenderSteps<'a, S> {
|
||||
im: RgbImage,
|
||||
sim: &'a dyn GenericSim,
|
||||
sim: &'a S,
|
||||
meas: &'a [Box<dyn AbstractMeasurement>],
|
||||
/// Simulation z coordinate to sample
|
||||
z: u32,
|
||||
}
|
||||
|
||||
impl<'a> RenderSteps<'a> {
|
||||
impl<'a, S: GenericSim> RenderSteps<'a, S> {
|
||||
/// Render using default configuration constants
|
||||
fn render(state: &'a dyn GenericSim, measurements: &'a [Box<dyn AbstractMeasurement>], z: u32) -> RgbImage {
|
||||
fn render(state: &'a S, measurements: &'a [Box<dyn AbstractMeasurement>], z: u32) -> RgbImage {
|
||||
Self::render_configured(state, measurements, z, (640, 480))
|
||||
}
|
||||
/// Render, controlling things like the size.
|
||||
fn render_configured(state: &'a dyn GenericSim, measurements: &'a [Box<dyn AbstractMeasurement>], z: u32, max_size: (u32, u32)) -> RgbImage {
|
||||
fn render_configured(state: &'a S, measurements: &'a [Box<dyn AbstractMeasurement>], z: u32, max_size: (u32, u32)) -> RgbImage {
|
||||
let (width, height) = im_size(state, max_size.0, max_size.1);
|
||||
trace!("rendering at {}x{} with z={}", width, height, z);
|
||||
let mut me = Self::new(state, measurements, width, height, z);
|
||||
@@ -109,7 +109,7 @@ impl<'a> RenderSteps<'a> {
|
||||
me.render_measurements();
|
||||
me.im
|
||||
}
|
||||
fn new(sim: &'a dyn GenericSim, meas: &'a [Box<dyn AbstractMeasurement>], width: u32, height: u32, z: u32) -> Self {
|
||||
fn new(sim: &'a S, meas: &'a [Box<dyn AbstractMeasurement>], width: u32, height: u32, z: u32) -> Self {
|
||||
RenderSteps {
|
||||
im: RgbImage::new(width, height),
|
||||
sim,
|
||||
@@ -259,20 +259,30 @@ impl ImageRenderExt for RgbImage {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Renderer: Send + Sync {
|
||||
fn render_z_slice(&self, state: &dyn GenericSim, z: u32, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
self.render_with_image(state, &RenderSteps::render(state, measurements, z), measurements);
|
||||
}
|
||||
fn render(&self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
self.render_z_slice(state, state.depth() / 2, measurements);
|
||||
}
|
||||
pub trait Renderer<S>: Send + Sync {
|
||||
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>]);
|
||||
// {
|
||||
// self.render_with_image(state, &RenderSteps::render(state, measurements, z), measurements);
|
||||
// }
|
||||
fn render(&self, state: &S, measurements: &[Box<dyn AbstractMeasurement>]);
|
||||
/// Not intended to be called directly by users; implement this if you want the image to be
|
||||
/// computed using default settings and you just manage where to display/save it.
|
||||
fn render_with_image(&self, state: &dyn GenericSim, _im: &RgbImage, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
fn render_with_image(&self, state: &S, _im: &RgbImage, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
self.render(state, measurements);
|
||||
}
|
||||
}
|
||||
|
||||
fn default_render_z_slice<S: GenericSim, R: Renderer<S>>(
|
||||
me: &R, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>]
|
||||
) {
|
||||
me.render_with_image(state, &RenderSteps::render(state, measurements, z), measurements);
|
||||
}
|
||||
fn default_render<S: GenericSim, R: Renderer<S>>(
|
||||
me: &R, state: &S, measurements: &[Box<dyn AbstractMeasurement>]
|
||||
) {
|
||||
me.render_z_slice(state, state.depth() / 2, measurements);
|
||||
}
|
||||
|
||||
// pub struct NumericTermRenderer;
|
||||
//
|
||||
// impl Renderer for NumericTermRenderer {
|
||||
@@ -296,8 +306,11 @@ pub trait Renderer: Send + Sync {
|
||||
#[derive(Default)]
|
||||
pub struct ColorTermRenderer;
|
||||
|
||||
impl Renderer for ColorTermRenderer {
|
||||
fn render_z_slice(&self, state: &dyn GenericSim, z: u32, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
impl<S: GenericSim> Renderer<S> for ColorTermRenderer {
|
||||
fn render(&self, state: &S, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
default_render(self, state, measurements)
|
||||
}
|
||||
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
let (max_w, mut max_h) = crossterm::terminal::size().unwrap();
|
||||
max_h = max_h.saturating_sub(1 + measurements.len() as u16);
|
||||
let im = RenderSteps::render_configured(state, &[], z, (max_w as _, max_h as _));
|
||||
@@ -338,7 +351,7 @@ pub struct Y4MRenderer {
|
||||
}
|
||||
|
||||
impl Y4MRenderer {
|
||||
pub fn new<S: Into<PathBuf>>(output: S) -> Self {
|
||||
pub fn new<P: Into<PathBuf>>(output: P) -> Self {
|
||||
Self {
|
||||
out_path: output.into(),
|
||||
encoder: Mutex::new(None),
|
||||
@@ -346,8 +359,14 @@ impl Y4MRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer for Y4MRenderer {
|
||||
fn render_with_image(&self, _state: &dyn GenericSim, im: &RgbImage, _meas: &[Box<dyn AbstractMeasurement>]) {
|
||||
impl<S: GenericSim> Renderer<S> for Y4MRenderer {
|
||||
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
default_render_z_slice(self, state, z, measurements)
|
||||
}
|
||||
fn render(&self, state: &S, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
default_render(self, state, measurements)
|
||||
}
|
||||
fn render_with_image(&self, _state: &S, im: &RgbImage, _meas: &[Box<dyn AbstractMeasurement>]) {
|
||||
{
|
||||
let mut enc = self.encoder.lock().unwrap();
|
||||
if enc.is_none() {
|
||||
@@ -413,8 +432,11 @@ impl PlotlyRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer for PlotlyRenderer {
|
||||
fn render(&self, state: &dyn GenericSim, _meas: &[Box<dyn AbstractMeasurement>]) {
|
||||
impl<S: GenericSim> Renderer<S> for PlotlyRenderer {
|
||||
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
default_render_z_slice(self, state, z, measurements)
|
||||
}
|
||||
fn render(&self, state: &S, _meas: &[Box<dyn AbstractMeasurement>]) {
|
||||
use plotly::{ImageFormat, Plot, Rgba};
|
||||
// use plotly::common::Marker;
|
||||
use plotly::layout::{AspectMode, Axis, Layout, LayoutScene};
|
||||
@@ -442,7 +464,7 @@ impl Renderer for PlotlyRenderer {
|
||||
// if x%5 == 0 || y%5 == 0 || z%5 == 0 {
|
||||
// continue;
|
||||
// }
|
||||
let cell = state.get(Index(Vec3u::new(x, y, z)));
|
||||
let cell = (state as &dyn GenericSim).get(Index(Vec3u::new(x, y, z)));
|
||||
xv.push(x);
|
||||
yv.push(y);
|
||||
zv.push(z);
|
||||
@@ -480,32 +502,42 @@ impl Renderer for PlotlyRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MultiRenderer {
|
||||
renderers: RwLock<Vec<Box<dyn Renderer>>>,
|
||||
pub struct MultiRenderer<S> {
|
||||
renderers: RwLock<Vec<Box<dyn Renderer<S>>>>,
|
||||
}
|
||||
|
||||
impl MultiRenderer {
|
||||
impl<S> Default for MultiRenderer<S> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
renderers: RwLock::new(Vec::new())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> MultiRenderer<S> {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
pub fn push<R: Renderer + 'static>(&self, r: R) {
|
||||
pub fn push<R: Renderer<S> + 'static>(&self, r: R) {
|
||||
self.renderers.write().unwrap().push(Box::new(r));
|
||||
}
|
||||
pub fn with<R: Renderer + 'static>(self, r: R) -> Self {
|
||||
pub fn with<R: Renderer<S> + 'static>(self, r: R) -> Self {
|
||||
self.push(r);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer for MultiRenderer {
|
||||
fn render(&self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
impl<S: GenericSim> Renderer<S> for MultiRenderer<S> {
|
||||
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
default_render_z_slice(self, state, z, measurements)
|
||||
}
|
||||
fn render(&self, state: &S, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
if self.renderers.read().unwrap().len() != 0 {
|
||||
self.render_with_image(state, &RenderSteps::render(state, measurements, state.depth() / 2), measurements);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_with_image(&self, state: &dyn GenericSim, im: &RgbImage, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
fn render_with_image(&self, state: &S, im: &RgbImage, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
for r in &*self.renderers.read().unwrap() {
|
||||
r.render_with_image(state, im, measurements);
|
||||
}
|
||||
@@ -530,8 +562,11 @@ impl SerializerRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer for SerializerRenderer {
|
||||
fn render(&self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
impl<S: GenericSim> Renderer<S> for SerializerRenderer {
|
||||
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
default_render_z_slice(self, state, z, measurements)
|
||||
}
|
||||
fn render(&self, state: &S, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||
let snap = state.to_static();
|
||||
let frame = SerializedFrame {
|
||||
state: snap,
|
||||
|
Reference in New Issue
Block a user