Add renderer and mocks

This commit is contained in:
Nicolas 2022-04-09 16:07:49 +02:00
parent 26f4960276
commit 43cecf57b3
5 changed files with 102 additions and 3 deletions

View File

@ -10,4 +10,5 @@ repository = "https://github.com/ricoriedel/wipe"
anyhow = "1.0" anyhow = "1.0"
clap = { version = "3.1", features = ["derive"]} clap = { version = "3.1", features = ["derive"]}
crossterm = "0.23" crossterm = "0.23"
rand = "0.8" rand = "0.8"
mockall = "0.11"

View File

@ -10,6 +10,7 @@ use crate::color::{ColorSampler, SimpleColorSampler};
use crate::fill::circle::CircleFillMode; use crate::fill::circle::CircleFillMode;
use crate::fill::FillMode; use crate::fill::FillMode;
use crate::fill::level::LevelFillMode; use crate::fill::level::LevelFillMode;
use crate::render::{Renderer, SamplerRenderer};
use crate::sampler::ComposedSampler; use crate::sampler::ComposedSampler;
use crate::surface::WriteSurface; use crate::surface::WriteSurface;
use crate::vec::Vector; use crate::vec::Vector;
@ -22,6 +23,7 @@ mod array;
mod surface; mod surface;
mod animation; mod animation;
mod sampler; mod sampler;
mod render;
#[derive(Copy, Clone, ArgEnum)] #[derive(Copy, Clone, ArgEnum)]
enum AnimationType { enum AnimationType {
@ -76,8 +78,13 @@ fn main() -> Result<(), Error> {
let color = create_color(args.color[0]); let color = create_color(args.color[0]);
let char = Box::new(SimpleCharSampler::new(args.chars)); let char = Box::new(SimpleCharSampler::new(args.chars));
let _ = Box::new(ComposedSampler::new(animation, fill, color, char)); let sampler = Box::new(ComposedSampler::new(animation, fill, color, char));
let _ = Box::new(WriteSurface::new(stdout(), width, height)); let surface = Box::new(WriteSurface::new(stdout(), width, height));
let mut renderer = Box::new(SamplerRenderer::new(surface, sampler));
renderer.render(0.5);
renderer.present()?;
Ok(()) Ok(())
} }

87
src/render.rs Normal file
View File

@ -0,0 +1,87 @@
use anyhow::Error;
use crate::sampler::{Sample, Sampler};
use crate::surface::Surface;
use crate::Vector;
pub trait Renderer {
fn render(&mut self, step: f32);
fn present(&mut self) -> Result<(), Error>;
}
pub struct SamplerRenderer {
surface: Box<dyn Surface>,
sampler: Box<dyn Sampler>,
}
impl SamplerRenderer {
pub fn new(surface: Box<dyn Surface>,
sampler: Box<dyn Sampler>) -> Self {
Self { surface, sampler }
}
}
impl Renderer for SamplerRenderer {
fn render(&mut self, step: f32) {
for x in 0..self.surface.width() {
for y in 0..self.surface.height() {
let pos = Vector::from_terminal(x, y);
let sample = self.sampler.sample(step, pos);
match sample {
Sample::Keep => (),
Sample::Draw { char, color } => self.surface.draw(x, y, char, color),
Sample::Clear => self.surface.clear(x, y),
}
}
}
}
fn present(&mut self) -> Result<(), Error> {
self.surface.present()
}
}
#[cfg(test)]
mod test {
use crossterm::style::*;
use mockall::predicate::*;
use super::*;
use crate::surface::MockSurface;
use crate::sampler::MockSampler;
#[test]
fn render() {
let mut surface = Box::new(MockSurface::new());
let mut sampler = Box::new(MockSampler::new());
sampler.expect_sample().withf(|_, pos| pos.x == 0.0 && pos.y == 0.0).returning(|_,_| Sample::Clear);
sampler.expect_sample().withf(|_, pos| pos.x == 1.0 && pos.y == 0.0).returning(|_,_| Sample::Keep);
sampler.expect_sample().withf(|_, pos| pos.x == 0.0 && pos.y == 2.0).returning(|_,_| Sample::Draw { char: 'a', color: Color::Red });
sampler.expect_sample().withf(|_, pos| pos.x == 1.0 && pos.y == 2.0).returning(|_,_| Sample::Keep);
sampler.expect_sample().withf(|_, pos| pos.x == 0.0 && pos.y == 4.0).returning(|_,_| Sample::Draw { char: 'x', color: Color::Yellow });
sampler.expect_sample().withf(|_, pos| pos.x == 1.0 && pos.y == 4.0).returning(|_,_| Sample::Clear);
surface.expect_width().return_const(2 as usize);
surface.expect_height().return_const(3 as usize);
surface.expect_clear().once().with(eq(0), eq(0)).return_const(());
surface.expect_draw().once().with(eq(0), eq(1), eq('a'), eq(Color::Red)).return_const(());
surface.expect_draw().once().with(eq(0), eq(2), eq('x'), eq(Color::Yellow)).return_const(());
surface.expect_clear().once().with(eq(1), eq(2)).return_const(());
let mut renderer = SamplerRenderer::new(surface, sampler);
renderer.render(0.5);
}
#[test]
fn present() {
let mut surface = Box::new(MockSurface::new());
let sampler = Box::new(MockSampler::new());
surface.expect_present().once().returning(|| Ok(()));
let mut renderer = SamplerRenderer::new(surface, sampler);
renderer.present().unwrap();
}
}

View File

@ -1,4 +1,5 @@
use crossterm::style::Color; use crossterm::style::Color;
use mockall::automock;
use crate::animation::Animation; use crate::animation::Animation;
use crate::char::CharSampler; use crate::char::CharSampler;
use crate::color::ColorSampler; use crate::color::ColorSampler;
@ -11,6 +12,7 @@ pub enum Sample {
Clear, Clear,
} }
#[automock]
pub trait Sampler { pub trait Sampler {
fn sample(&self, step: f32, pos: Vector) -> Sample; fn sample(&self, step: f32, pos: Vector) -> Sample;
} }

View File

@ -3,9 +3,11 @@ use crossterm::cursor::MoveTo;
use crossterm::{ExecutableCommand, QueueableCommand}; use crossterm::{ExecutableCommand, QueueableCommand};
use crossterm::style::{Color, Print, SetForegroundColor}; use crossterm::style::{Color, Print, SetForegroundColor};
use crossterm::terminal::{Clear, ClearType}; use crossterm::terminal::{Clear, ClearType};
use mockall::automock;
use std::io::Write; use std::io::Write;
use crate::array::Array2D; use crate::array::Array2D;
#[automock]
pub trait Surface { pub trait Surface {
fn width(&self) -> usize; fn width(&self) -> usize;
fn height(&self) -> usize; fn height(&self) -> usize;