logo_renderer/
lib.rs

1mod fill;
2
3use wasm_bindgen::prelude::*;
4
5pub use logo_runtime;
6
7use raqote::*;
8use logo_runtime::colors::LogoColor;
9use logo_runtime::common::Pos;
10use logo_runtime::drawinglib::add_drawinglib;
11use logo_runtime::logo_interp::executor::execute_str;
12use logo_runtime::logo_interp::executor_state::EState;
13use logo_runtime::logo_interp::stdlib::add_stdlib;
14use logo_runtime::state::{Delegate, State};
15use crate::fill::flood_fill;
16
17pub struct DrawingDelegate {
18    pub dt: DrawTarget,
19    pub show_fn: Option<Box<dyn Fn(&str)>>,
20}
21
22impl DrawingDelegate {
23    fn transform_coords(&self, pos: Pos) -> (f32, f32) {
24        let width = self.dt.width() as f64;
25        let height = self.dt.height() as f64;
26        ((pos.x + width / 2f64 + 0.5) as f32, (-pos.y + height / 2f64 + 0.5) as f32)
27    }
28}
29
30impl Delegate for DrawingDelegate {
31    fn clear_graphics(&mut self) {
32        self.dt.clear(SolidSource{
33            r: 255,
34            g: 255,
35            b: 255,
36            a: 255,
37        });
38    }
39
40    fn draw_line(&mut self, from: Pos, to: Pos, pen_size: f64, color: LogoColor) {
41        let upd_from = self.transform_coords(from);
42        let upd_to = self.transform_coords(to);
43        let mut pb = PathBuilder::new();
44        pb.move_to(upd_from.0, upd_from.1);
45        pb.line_to(upd_to.0, upd_to.1);
46        let path = pb.finish();
47        self.dt.stroke(&path, &Source::Solid(SolidSource {
48                r: color.r,
49                g: color.g,
50                b: color.b,
51                a: 255
52            }),
53            &StrokeStyle {
54                width: pen_size as f32,
55                cap: LineCap::Square,
56                ..StrokeStyle::default()
57            },
58            &DrawOptions::new()
59        );
60    }
61
62    fn fill(&mut self, pos: Pos, color: LogoColor) {
63        let upd_pos = self.transform_coords(pos);
64        flood_fill(self.dt.width(), self.dt.height(), self.dt.get_data_u8_mut(),
65            upd_pos.0 as i32, upd_pos.1 as i32, color);
66    }
67
68    fn show(&mut self, message: &str) {
69        if let Some(show_fn) = &self.show_fn {
70            (show_fn)(message);
71        }
72    }
73}
74
75#[wasm_bindgen]
76pub struct Context {
77    #[wasm_bindgen(skip)]
78    pub state: EState<State<DrawingDelegate>>,
79}
80
81impl Context {
82    pub fn new(width: i32, height: i32) -> Self {
83        let dt = DrawTarget::new(width, height);
84        let dd = DrawingDelegate { dt, show_fn: None };
85        let mut state = EState::new(State::new(width, height, dd));
86        state.state.delegate.clear_graphics();
87        add_stdlib(&mut state);
88        add_drawinglib(&mut state);
89        return Self {state}
90    }
91
92    pub fn render(&mut self, proc_source: &str, cmd_source: &str) -> Result<Vec<u8>, String> {
93        execute_str(&mut self.state, proc_source, cmd_source)?;
94        Ok(Vec::from(self.state.state.delegate.dt.get_data_u8()))
95    }
96}
97