mraphics_native/
canvas.rs

1use mraphics_core::{
2    Animation, Color, Geometry, LogicalTimeline, Material, MeshLike, PerspectiveCamera, Renderer,
3    Scene, Timeline,
4};
5use std::{cell::RefCell, rc::Rc, sync::Arc, time::Duration};
6use winit::{event::WindowEvent, event_loop::EventLoop, window::Window};
7
8pub struct Canvas {
9    pub window: Option<Arc<Window>>,
10    pub camera: PerspectiveCamera,
11    pub renderer: Option<Renderer<'static>>,
12    pub scene: Rc<RefCell<Scene>>,
13
14    pub timeline: Rc<RefCell<Box<dyn Timeline>>>,
15    pub playhead: f32,
16
17    pub clear_color: Color<f64>,
18
19    pub on_window_event:
20        Box<dyn FnMut(&winit::event_loop::ActiveEventLoop, &WindowEvent, &mut PerspectiveCamera)>,
21}
22
23impl Canvas {
24    pub fn new() -> Self {
25        Self {
26            window: None,
27            camera: PerspectiveCamera::default(),
28            renderer: None,
29            scene: Rc::new(RefCell::new(Scene::new())),
30
31            timeline: Rc::new(RefCell::new(Box::new(LogicalTimeline::new()))),
32            playhead: 0.0,
33
34            clear_color: Color::from_hex_str(mraphics_core::constants::GRAY_E).unwrap(),
35
36            on_window_event: Box::new(|_, _, _| {}),
37        }
38    }
39
40    pub fn add_mesh<G: Geometry, M: Material, Mesh: MeshLike<G, M>>(&self, mesh: &Mesh) {
41        self.scene.borrow_mut().add_renderable(mesh);
42
43        mesh.geometry().update_view(
44            &mut self
45                .scene
46                .borrow_mut()
47                .acquire_instance_mut(mesh.identifier())
48                .unwrap()
49                .geometry,
50        );
51        mesh.material().update_view(
52            &mut self
53                .scene
54                .borrow_mut()
55                .acquire_instance_mut(mesh.identifier())
56                .unwrap()
57                .material,
58        );
59    }
60
61    pub fn run(&mut self) {
62        let event_loop = EventLoop::new().unwrap();
63        event_loop.run_app(self).unwrap();
64    }
65
66    pub fn queue_animation<Ani: Animation>(&mut self, animation: Ani, duration: &Duration) {
67        let mut action = animation.into_action(self.scene.clone());
68        action.duration = duration.as_secs_f32();
69        action.start_time = self.playhead;
70
71        self.playhead += action.duration;
72
73        self.timeline.borrow_mut().add_action(action);
74    }
75
76    pub fn advance_playhead(&mut self, step: &Duration) {
77        self.playhead += step.as_secs_f32();
78    }
79
80    pub fn with_scene_timeline_handle<
81        F: FnMut(Rc<RefCell<Scene>>, Rc<RefCell<Box<dyn Timeline>>>),
82    >(
83        &self,
84        mut closure: F,
85    ) {
86        closure(self.scene.clone(), self.timeline.clone())
87    }
88}
89
90impl winit::application::ApplicationHandler for Canvas {
91    fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
92        let window = event_loop
93            .create_window(Window::default_attributes().with_title("mraphics window"))
94            .unwrap();
95
96        self.window = Some(Arc::new(window));
97
98        let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
99            backends: wgpu::Backends::PRIMARY,
100            ..Default::default()
101        });
102
103        let surface = instance
104            .create_surface(Arc::clone(self.window.as_ref().unwrap()))
105            .unwrap();
106
107        pollster::block_on(async {
108            let adapter = instance
109                .request_adapter(&wgpu::RequestAdapterOptions {
110                    force_fallback_adapter: false,
111                    compatible_surface: Some(&surface),
112                    ..Default::default()
113                })
114                .await
115                .unwrap();
116
117            let (device, queue) = adapter
118                .request_device(&wgpu::DeviceDescriptor::default())
119                .await
120                .unwrap();
121
122            self.renderer = Some(Renderer::new(surface, device, queue, &adapter));
123        });
124    }
125
126    fn window_event(
127        &mut self,
128        event_loop: &winit::event_loop::ActiveEventLoop,
129        _window_id: winit::window::WindowId,
130        event: winit::event::WindowEvent,
131    ) {
132        match event {
133            WindowEvent::CloseRequested => {
134                event_loop.exit();
135            }
136            WindowEvent::Resized(size) => {
137                self.camera
138                    .set_aspect(size.width as f32 / size.height as f32);
139
140                self.renderer
141                    .as_mut()
142                    .unwrap()
143                    .resize(size.width, size.height);
144            }
145            WindowEvent::RedrawRequested => {
146                self.timeline.borrow_mut().forward();
147
148                self.renderer
149                    .as_mut()
150                    .unwrap()
151                    .render(
152                        &mut self.scene.borrow_mut(),
153                        &self.camera,
154                        &self.clear_color,
155                    )
156                    .unwrap();
157
158                self.window.as_ref().unwrap().request_redraw();
159            }
160            _ => {}
161        }
162
163        (self.on_window_event)(event_loop, &event, &mut self.camera);
164    }
165}