mraphics_native/
canvas.rs1use 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}