mirror of
https://github.com/ricoriedel/wipe.git
synced 2024-11-22 16:06:38 +00:00
Add renderer
This commit is contained in:
parent
f5730be835
commit
ef4eaec34d
@ -2,6 +2,7 @@ pub mod convert;
|
|||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod pattern;
|
pub mod pattern;
|
||||||
pub mod printer;
|
pub mod printer;
|
||||||
|
mod renderer;
|
||||||
pub mod term;
|
pub mod term;
|
||||||
mod vec;
|
mod vec;
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
mod circle;
|
pub mod circle;
|
||||||
mod line;
|
pub mod line;
|
||||||
mod rhombus;
|
pub mod rhombus;
|
||||||
mod wheel;
|
pub mod wheel;
|
||||||
|
|
||||||
use crate::vec::Vector;
|
use crate::vec::Vector;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub size: Vector,
|
pub size: Vector,
|
||||||
pub step: f32,
|
pub step: f32,
|
||||||
@ -22,8 +22,11 @@ pub trait Pattern {
|
|||||||
fn sample(&self, pos: Vector) -> f32;
|
fn sample(&self, pos: Vector) -> f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(test, mockall::automock(type Sampler = MockSampler;))]
|
||||||
pub trait SamplerFactory {
|
pub trait SamplerFactory {
|
||||||
fn create(&self, config: &Config) -> Box<dyn Sampler>;
|
type Sampler: Sampler;
|
||||||
|
|
||||||
|
fn create(&self, config: &Config) -> Self::Sampler;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(test, mockall::automock)]
|
#[cfg_attr(test, mockall::automock)]
|
||||||
@ -46,11 +49,10 @@ pub struct SamplerImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SamplerFactory for SamplerFactoryImpl {
|
impl SamplerFactory for SamplerFactoryImpl {
|
||||||
fn create(&self, config: &Config) -> Box<dyn Sampler> {
|
type Sampler = SamplerImpl;
|
||||||
Box::new(SamplerImpl::new(
|
|
||||||
self.char.create(config),
|
fn create(&self, config: &Config) -> Self::Sampler {
|
||||||
self.color.create(config),
|
SamplerImpl::new(self.char.create(config), self.color.create(config))
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ use crossterm::cursor::*;
|
|||||||
use crossterm::style::*;
|
use crossterm::style::*;
|
||||||
use crossterm::terminal::*;
|
use crossterm::terminal::*;
|
||||||
|
|
||||||
|
#[cfg_attr(test, mockall::automock)]
|
||||||
pub trait Printer {
|
pub trait Printer {
|
||||||
fn show_cursor(&mut self) -> Result<(), Error>;
|
fn show_cursor(&mut self) -> Result<(), Error>;
|
||||||
fn hide_cursor(&mut self) -> Result<(), Error>;
|
fn hide_cursor(&mut self) -> Result<(), Error>;
|
||||||
|
271
src/renderer.rs
Normal file
271
src/renderer.rs
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
use crate::convert::char::CharSample;
|
||||||
|
use crate::convert::Converter;
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::pattern::{Config, Sampler, SamplerFactory};
|
||||||
|
use crate::printer::Printer;
|
||||||
|
use crate::vec::Vector;
|
||||||
|
|
||||||
|
pub trait Renderer {
|
||||||
|
fn begin(&mut self) -> Result<(), Error>;
|
||||||
|
fn render(&mut self, step: f32) -> Result<(), Error>;
|
||||||
|
fn end(&mut self) -> Result<(), Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(derive_more::Constructor)]
|
||||||
|
pub struct RendererImpl<T1, T2, T3> {
|
||||||
|
sampler: T1,
|
||||||
|
converter: T2,
|
||||||
|
printer: T3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1: SamplerFactory, T2: Converter, T3: Printer> Renderer for RendererImpl<T1, T2, T3> {
|
||||||
|
fn begin(&mut self) -> Result<(), Error> {
|
||||||
|
self.printer.hide_cursor()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&mut self, step: f32) -> Result<(), Error> {
|
||||||
|
let (width, height) = self.printer.size()?;
|
||||||
|
let config = Config {
|
||||||
|
step,
|
||||||
|
size: Vector::from_terminal(width, height),
|
||||||
|
};
|
||||||
|
let sampler = self.sampler.create(&config);
|
||||||
|
|
||||||
|
for y in 0..height {
|
||||||
|
for x in 0..width {
|
||||||
|
let pos = Vector::from_terminal(x, y);
|
||||||
|
|
||||||
|
match self.converter.char(sampler.char(pos)) {
|
||||||
|
CharSample::Draw(char) => {
|
||||||
|
let color = self.converter.color(sampler.color(pos));
|
||||||
|
|
||||||
|
self.printer.move_to(x, y)?;
|
||||||
|
self.printer.set_foreground(color)?;
|
||||||
|
self.printer.print(char)?;
|
||||||
|
}
|
||||||
|
CharSample::Clear => {
|
||||||
|
self.printer.move_to(x, y)?;
|
||||||
|
self.printer.print(' ')?;
|
||||||
|
}
|
||||||
|
CharSample::Keep => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.printer.flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(&mut self) -> Result<(), Error> {
|
||||||
|
self.printer.move_to(0, 0)?;
|
||||||
|
self.printer.clear()?;
|
||||||
|
self.printer.show_cursor()?;
|
||||||
|
self.printer.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use crate::convert::MockConverter;
|
||||||
|
use crate::pattern::MockSampler;
|
||||||
|
use crate::pattern::MockSamplerFactory;
|
||||||
|
use crate::printer::MockPrinter;
|
||||||
|
use crossterm::style::Color;
|
||||||
|
use mockall::predicate::eq;
|
||||||
|
use mockall::Sequence;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn begin() {
|
||||||
|
let factory = MockSamplerFactory::new();
|
||||||
|
let converter = MockConverter::new();
|
||||||
|
let mut printer = MockPrinter::new();
|
||||||
|
|
||||||
|
printer.expect_hide_cursor().once().returning(|| Ok(()));
|
||||||
|
|
||||||
|
let mut renderer = RendererImpl::new(factory, converter, printer);
|
||||||
|
|
||||||
|
renderer.begin().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn render_config_correct() {
|
||||||
|
let mut sampler = MockSamplerFactory::new();
|
||||||
|
let mut converter = MockConverter::new();
|
||||||
|
let mut printer = MockPrinter::new();
|
||||||
|
|
||||||
|
printer.expect_size().returning(|| Ok((2, 2)));
|
||||||
|
sampler.expect_create().returning(|_| {
|
||||||
|
let mut sampler = MockSampler::new();
|
||||||
|
sampler
|
||||||
|
.expect_char()
|
||||||
|
.with(eq(Vector::new(0.0, 0.0)))
|
||||||
|
.return_const(1.0);
|
||||||
|
sampler
|
||||||
|
.expect_char()
|
||||||
|
.with(eq(Vector::new(1.0, 0.0)))
|
||||||
|
.return_const(2.0);
|
||||||
|
sampler
|
||||||
|
.expect_char()
|
||||||
|
.with(eq(Vector::new(0.0, 2.0)))
|
||||||
|
.return_const(3.0);
|
||||||
|
sampler
|
||||||
|
.expect_char()
|
||||||
|
.with(eq(Vector::new(1.0, 2.0)))
|
||||||
|
.return_const(4.0);
|
||||||
|
sampler
|
||||||
|
.expect_color()
|
||||||
|
.with(eq(Vector::new(0.0, 0.0)))
|
||||||
|
.return_const(5.0);
|
||||||
|
sampler
|
||||||
|
.expect_color()
|
||||||
|
.with(eq(Vector::new(1.0, 0.0)))
|
||||||
|
.return_const(6.0);
|
||||||
|
sampler
|
||||||
|
.expect_color()
|
||||||
|
.with(eq(Vector::new(0.0, 2.0)))
|
||||||
|
.return_const(7.0);
|
||||||
|
sampler
|
||||||
|
.expect_color()
|
||||||
|
.with(eq(Vector::new(1.0, 2.0)))
|
||||||
|
.return_const(8.0);
|
||||||
|
sampler
|
||||||
|
});
|
||||||
|
converter
|
||||||
|
.expect_char()
|
||||||
|
.with(eq(1.0))
|
||||||
|
.return_const(CharSample::Keep);
|
||||||
|
converter
|
||||||
|
.expect_char()
|
||||||
|
.with(eq(2.0))
|
||||||
|
.return_const(CharSample::Clear);
|
||||||
|
converter
|
||||||
|
.expect_char()
|
||||||
|
.with(eq(3.0))
|
||||||
|
.return_const(CharSample::Draw('A'));
|
||||||
|
converter
|
||||||
|
.expect_char()
|
||||||
|
.with(eq(4.0))
|
||||||
|
.return_const(CharSample::Draw('X'));
|
||||||
|
converter
|
||||||
|
.expect_color()
|
||||||
|
.with(eq(7.0))
|
||||||
|
.return_const(Color::Red);
|
||||||
|
converter
|
||||||
|
.expect_color()
|
||||||
|
.with(eq(8.0))
|
||||||
|
.return_const(Color::Blue);
|
||||||
|
|
||||||
|
let seq = &mut Sequence::new();
|
||||||
|
|
||||||
|
printer
|
||||||
|
.expect_move_to()
|
||||||
|
.once()
|
||||||
|
.with(eq(1), eq(0))
|
||||||
|
.returning(|_, _| Ok(()))
|
||||||
|
.in_sequence(seq);
|
||||||
|
printer
|
||||||
|
.expect_print()
|
||||||
|
.once()
|
||||||
|
.with(eq(' '))
|
||||||
|
.returning(|_| Ok(()))
|
||||||
|
.in_sequence(seq);
|
||||||
|
printer
|
||||||
|
.expect_move_to()
|
||||||
|
.once()
|
||||||
|
.with(eq(0), eq(1))
|
||||||
|
.returning(|_, _| Ok(()))
|
||||||
|
.in_sequence(seq);
|
||||||
|
printer
|
||||||
|
.expect_set_foreground()
|
||||||
|
.once()
|
||||||
|
.with(eq(Color::Red))
|
||||||
|
.returning(|_| Ok(()))
|
||||||
|
.in_sequence(seq);
|
||||||
|
printer
|
||||||
|
.expect_print()
|
||||||
|
.once()
|
||||||
|
.with(eq('A'))
|
||||||
|
.returning(|_| Ok(()))
|
||||||
|
.in_sequence(seq);
|
||||||
|
printer
|
||||||
|
.expect_move_to()
|
||||||
|
.once()
|
||||||
|
.with(eq(1), eq(1))
|
||||||
|
.returning(|_, _| Ok(()))
|
||||||
|
.in_sequence(seq);
|
||||||
|
printer
|
||||||
|
.expect_set_foreground()
|
||||||
|
.once()
|
||||||
|
.with(eq(Color::Blue))
|
||||||
|
.returning(|_| Ok(()))
|
||||||
|
.in_sequence(seq);
|
||||||
|
printer
|
||||||
|
.expect_print()
|
||||||
|
.once()
|
||||||
|
.with(eq('X'))
|
||||||
|
.returning(|_| Ok(()))
|
||||||
|
.in_sequence(seq);
|
||||||
|
printer
|
||||||
|
.expect_flush()
|
||||||
|
.once()
|
||||||
|
.returning(|| Ok(()))
|
||||||
|
.in_sequence(seq);
|
||||||
|
|
||||||
|
let mut renderer = RendererImpl::new(sampler, converter, printer);
|
||||||
|
|
||||||
|
renderer.render(0.0).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn render() {
|
||||||
|
let mut sampler = MockSamplerFactory::new();
|
||||||
|
let mut converter = MockConverter::new();
|
||||||
|
let mut printer = MockPrinter::new();
|
||||||
|
|
||||||
|
sampler.expect_create().returning(|_| {
|
||||||
|
let mut sampler = MockSampler::new();
|
||||||
|
sampler.expect_char().return_const(0.0);
|
||||||
|
sampler
|
||||||
|
});
|
||||||
|
converter.expect_char().return_const(CharSample::Keep);
|
||||||
|
printer.expect_size().returning(|| Ok((3, 2)));
|
||||||
|
printer.expect_flush().returning(|| Ok(()));
|
||||||
|
|
||||||
|
let mut renderer = RendererImpl::new(sampler, converter, printer);
|
||||||
|
|
||||||
|
renderer.render(0.8).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn end() {
|
||||||
|
let factory = MockSamplerFactory::new();
|
||||||
|
let converter = MockConverter::new();
|
||||||
|
let mut printer = MockPrinter::new();
|
||||||
|
|
||||||
|
let seq = &mut Sequence::new();
|
||||||
|
printer
|
||||||
|
.expect_move_to()
|
||||||
|
.with(eq(0), eq(0))
|
||||||
|
.once()
|
||||||
|
.returning(|_, _| Ok(()))
|
||||||
|
.in_sequence(seq);
|
||||||
|
printer
|
||||||
|
.expect_clear()
|
||||||
|
.once()
|
||||||
|
.returning(|| Ok(()))
|
||||||
|
.in_sequence(seq);
|
||||||
|
printer
|
||||||
|
.expect_show_cursor()
|
||||||
|
.once()
|
||||||
|
.returning(|| Ok(()))
|
||||||
|
.in_sequence(seq);
|
||||||
|
printer
|
||||||
|
.expect_flush()
|
||||||
|
.once()
|
||||||
|
.returning(|| Ok(()))
|
||||||
|
.in_sequence(seq);
|
||||||
|
|
||||||
|
let mut renderer = RendererImpl::new(factory, converter, printer);
|
||||||
|
|
||||||
|
renderer.end().unwrap();
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,10 @@ impl Vector {
|
|||||||
Self { x, y }
|
Self { x, y }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_terminal(x: u16, y: u16) -> Self {
|
||||||
|
Vector::new(x as f32, y as f32 * 2.0)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> f32 {
|
pub fn len(&self) -> f32 {
|
||||||
(self.x * self.x + self.y * self.y).sqrt()
|
(self.x * self.x + self.y * self.y).sqrt()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user