1pub mod display;
2pub mod run;
3pub mod device;
4pub mod vec_buffer;
5
6use std::sync::mpsc::Sender;
7use std::sync::Arc;
8use std::sync::Mutex;
9use std::time::Duration;
10use std::time::Instant;
11
12use winit::event::MouseButton;
13use winit::event_loop::EventLoopProxy;
14use winit::window::WindowId;
15
16use std::collections::VecDeque;
17
18use sketchbook::aspects::*;
19use sketchbook::compose;
20
21use crate::double_buffer::*;
22use crate::fifo::{FiFo, FiFoPop, FiFoPush};
23
24use self::display::Frame;
25use self::display::shape::shape_to_raw;
26
27pub use winit::event::VirtualKeyCode as Key;
28use sketchbook::compose::AsPart;
29
30pub struct TypeHolder;
31
32compose! {
33    pub enum Events {
34        #[part]
35        Update(update::env_api::Events<TypeHolder>),
36        #[part]
37        Draw(draw::env_api::Events<TypeHolder>),
38        #[part]
39        Mouse(mouse::env_api::Events<TypeHolder>),
40        #[part]
41        Keyboard(keyboard::env_api::Events<TypeHolder>),
42        Close,
43    }
44}
45
46pub struct DisplayInfo {
47    width: f32,
48    height: f32,
49    bridge: Option<DisplayBridge>,
50}
51
52#[derive(Debug, Clone)]
53pub enum DisplayEvent {
54    Redraw(WindowId),
55    Close(WindowId),
56}
57
58pub struct DisplayBridge {
59    pub window_id: WindowId,
60    pub event_loop: EventLoopProxy<DisplayEvent>,
61}
62
63compose! {
64    pub struct Page {
65        event_queue: FiFoPop<Events>,
66        shapes: DoubleBufferWrite<Frame>,
67        info: Arc<Mutex<DisplayInfo>>,
68        bridge: Option<DisplayBridge>,
69
70        #[part]
71        update_data: update::env_api::PageData<TypeHolder>,
72        #[part]
73        draw_data: draw::env_api::PageData<TypeHolder>,
74        #[part]
75        mouse_data: mouse::env_api::PageData<TypeHolder>,
76        #[part]
77        keyboard_data: keyboard::env_api::PageData<TypeHolder>,
78
79        update_impl: update::UpdateUsingInstant,
80        last_draw: Option<Instant>,
81
82        did_draw_this_group: bool,
83        events_for_group: VecDeque<Events>,
84    }
85}
86
87struct CreateWindow {
88    event_queue: FiFoPush<Events>,
89    shapes: DoubleBufferRead<Frame>,
90    info: Arc<Mutex<DisplayInfo>>,
91}
92
93#[derive(Clone)]
94pub struct Mill {
95    create_windows: Sender<CreateWindow>,
96}
97
98#[derive(Default)]
99pub struct Env;
100
101impl sketchbook::Environment for Env {
102    type Mill = Mill;
103
104    fn run<F>(self, func: F)
105    where
106        F: FnMut(&mut Self::Mill) -> sketchbook::Status + 'static,
107    {
108        run::run(self, func);
109    }
110}
111
112impl sketchbook::Mill for Mill {
113    type Page = Page;
114
115    fn new_page(&mut self) -> Self::Page {
116        let (event_sender, event_receiver) = FiFo::new(1000).split();
118        let info = Arc::new(Mutex::new(DisplayInfo {
119            width: 0.,
120            height: 0.,
121            bridge: None,
122        }));
123        let buffer = DoubleBuffer::new();
124        let (read, write) = buffer.split();
125        {
126            self.create_windows
127                .send(CreateWindow {
128                    event_queue: event_sender,
129                    shapes: read,
130                    info: info.clone(),
131                })
132                .unwrap();
133        }
134        Page {
135            did_draw_this_group: false,
136            events_for_group: VecDeque::new(),
137            bridge: None,
138            event_queue: event_receiver,
139            update_impl: update::UpdateUsingInstant::default(),
140            last_draw: None,
141            update_data: update::env_api::PageData::default(),
142            shapes: write,
143            draw_data: draw::env_api::PageData::default(),
144            mouse_data: mouse::env_api::PageData::default(),
145            keyboard_data: keyboard::env_api::PageData::default(),
146            info,
147        }
148    }
149}
150
151impl update::GetTime for Page {
152    type Time = Instant;
153    type Duration = Duration;
154
155    fn get_time(&mut self) -> Instant {
156        Instant::now()
157    }
158
159    fn zero_duration() -> Duration {
160        Duration::from_millis(0)
161    }
162
163    fn duration_between(start: &Instant, end: &Instant) -> Duration {
164        end.duration_since(*start)
165    }
166}
167
168impl keyboard::env_api::AssociatedTypes for TypeHolder {
169    type Key = Key;
170}
171
172impl keyboard::env_api::EnvAssociatedTypes for Env {
173    type AssociatedTypesHolder = TypeHolder;
174}
175
176impl update::env_api::AssociatedTypes for TypeHolder {
177    type Time = Instant;
178    type DeltaT = Duration;
179    type UpdateRate = f32;
180}
181
182impl update::UpdateDefaults for TypeHolder {
183    type DefaultUpdateRate = f32;
184    
185    fn default_update_rate() -> Self::DefaultUpdateRate {
186        30.0
187    }
188}
189
190impl update::env_api::EnvAssociatedTypes for Env {
191    type AssociatedTypesHolder = TypeHolder;
192}
193
194impl update::env_api::EnvAssociatedTypes for Page {
195    type AssociatedTypesHolder = TypeHolder;
196}
197
198impl draw::env_api::AssociatedTypes for TypeHolder {
199    type Real = f32;
200    type Color = palette::Srgba<u8>;
201}
202
203impl draw::DrawDefaults for TypeHolder {
204    type DefaultReal = f32;
205    type DefaultColor = palette::Srgba<u8>;
206
207    fn default_size() -> sketchbook::Size2<Self::DefaultReal> {
208        sketchbook::Size2 { width: 1.0, height: 1.0 }    
209    }
210
211    fn default_context() -> draw::Context<Self::DefaultReal, Self::DefaultColor> {
212        draw::Context {
213            fill: palette::Srgba::new(255, 255, 255, 255),
214            stroke: palette::Srgba::new(0, 0, 0, 255),
215            weight: 0.0,
216            rectangle_mode: draw::Mode::Center,
217            ellipse_mode: draw::Mode::Center,
218            rotation: 0.0,
219        }
220    }
221
222    fn default_background() -> Self::DefaultColor {
223        palette::Srgba::new(10, 10, 10, 255)
224    }
225
226    fn default_frame_rate() -> Self::DefaultReal {
227        30.0
228    }
229}
230
231impl draw::env_api::EnvAssociatedTypes for Env {
232    type AssociatedTypesHolder = TypeHolder;
233}
234
235impl draw::env_api::EnvAssociatedTypes for Page {
236    type AssociatedTypesHolder = TypeHolder;
237}
238
239impl mouse::env_api::AssociatedTypes for TypeHolder {
240    type Button = MouseButton;
241    type WheelCount = f32;
242    type Position = f32;
243}
244
245impl mouse::env_api::EnvAssociatedTypes for Env {
246    type AssociatedTypesHolder = TypeHolder;
247}
248
249impl sketchbook::Page for Page {
250    type Event = Events;
251
252    fn start_group(&mut self) {
253        let (width, height) = {
258            let mut info = self.info.lock().unwrap();
259            if let Some(bridge) = info.bridge.take() {
260                self.bridge = Some(bridge);
261            }
262            (info.width, info.height)
263        };
264        self.draw_data.set_size(sketchbook::Size2 { width, height });
265
266        for _ in 0..100 {
270            if let Some(event) = self.event_queue.pop() {
271                self.events_for_group.push_back(event);
272            } else {
273                break;
274            }
275        }
276
277        if self.update_impl.should_update(self.update_data.update_rate()) {
282            self.events_for_group.push_back(Events::Update(update::env_api::Events::Update));
283        }
284
285        if let Some(last_draw) = self.last_draw {
286            if last_draw.elapsed().as_secs_f32() >= 1.0 / self.draw_data.frame_rate() {
287                self.last_draw = Some(Instant::now());
288                self.events_for_group.push_back(Events::Draw(draw::env_api::Events::Draw));
289            }
290        } else {
291            self.last_draw = Some(Instant::now());
292            self.events_for_group.push_back(Events::Draw(draw::env_api::Events::Draw));
293        }
294
295        self.did_draw_this_group = false;
297    }
298
299    fn end_group(&mut self) {
300        if !self.events_for_group.is_empty() {
301            eprintln!("Event buffer was not completely processed. Events will roll over to next group.");
302        }
303
304        if self.did_draw_this_group {
306            let background = self.draw_data.background_color();
307            self.shapes.background = wgpu::Color {
308                r: background.red as f64 / 255.0,
309                g: background.green as f64 / 255.0,
310                b: background.blue as f64 / 255.0,
311                a: background.alpha as f64 / 255.0,
312            };
313
314            self.shapes.buffer.clear();
316
317            self.shapes.buffer.extend(self.draw_data.frame_mut().iter().map(|shape| shape_to_raw(shape)));
319
320            if self.draw_data.frame_mut().len() > 1_000_000 {
322                eprintln!("Frame buffer has {} shapes.", self.draw_data.frame_mut().len())
323            }
324
325            DoubleBufferWrite::swap(&mut self.shapes);
327
328            if let Some(bridge) = &self.bridge {
330                bridge
331                    .event_loop
332                    .send_event(DisplayEvent::Redraw(bridge.window_id))
333                    .ok();
334            }
335        }
336    }
337
338    fn next_event_in_group(&mut self) -> Option<Self::Event> {
339        self.events_for_group.pop_front()
340    }
341    
342    fn before_event(&mut self, event: &Self::Event) {
343        }
345
346    fn finish_event(&mut self, event: Self::Event) {
347        match event {
348            Events::Draw(_) => {
349                self.did_draw_this_group = true;
351            },
352            Events::Close => {
353                self.update_data.stop();
355            },
356            _ => {},
357        }
358    }
359
360    fn status(&self) -> sketchbook::Status {
361        if self.update_data.should_stop() {
362            sketchbook::Status::Stop
363        } else {
364            sketchbook::Status::Continue
365        }
366    }
367}
368
369impl Drop for Page {
370    fn drop(&mut self) {
371        if let Some(bridge) = &self.bridge {
373            bridge
374                .event_loop
375                .send_event(DisplayEvent::Close(bridge.window_id))
376                .ok();
377        }
378    }
379}