Skip to main content

radiantkit_core/
scene.rs

1use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
2
3use crate::{
4    ColorComponent, RadiantDocumentNode, RadiantInteractionManager, RadiantNode,
5    RadiantRenderManager, RadiantSceneMessage, RadiantSceneResponse, RadiantTessellatable,
6    RadiantTextureManager, RadiantTool, RadiantToolManager, RadiantTransformable, ScreenDescriptor,
7    TransformComponent,
8};
9use epaint::{text::FontDefinitions, ClippedPrimitive, Fonts, TextureId};
10
11pub struct RadiantScene<M, N: RadiantNode> {
12    pub document: Arc<RwLock<RadiantDocumentNode<N>>>,
13
14    pub screen_descriptor: ScreenDescriptor,
15
16    pub fonts_manager: epaint::Fonts,
17    pub render_manager: RadiantRenderManager,
18    pub tool_manager: RadiantToolManager<M>,
19    pub interaction_manager: RadiantInteractionManager<M>,
20    pub texture_manager: RadiantTextureManager,
21}
22
23impl<M: From<RadiantSceneMessage> + TryInto<RadiantSceneMessage>, N: RadiantNode>
24    RadiantScene<M, N>
25{
26    pub fn document(&self) -> RwLockReadGuard<RadiantDocumentNode<N>> {
27        self.document.read().unwrap()
28    }
29
30    pub fn document_mut(&mut self) -> RwLockWriteGuard<RadiantDocumentNode<N>> {
31        self.document.write().unwrap()
32    }
33
34    pub fn new(
35        config: wgpu::SurfaceConfiguration,
36        surface: wgpu::Surface,
37        device: wgpu::Device,
38        queue: wgpu::Queue,
39        screen_descriptor: ScreenDescriptor,
40        default_tool: impl RadiantTool<M> + 'static + Send + Sync,
41    ) -> Self {
42        let font_definitions = FontDefinitions::default();
43        let fonts_manager = Fonts::new(screen_descriptor.pixels_per_point, 1600, font_definitions);
44        let texture_manager = RadiantTextureManager::default();
45        let render_manager = RadiantRenderManager::new(config, surface, device, queue, None);
46
47        // let mut tool_manager = RadiantToolManager::new(Box::new(SelectionTool::new()));
48        // tool_manager.register_tool(Box::new(PathTool::new()));
49
50        Self {
51            document: Arc::new(RwLock::new(RadiantDocumentNode::new())),
52
53            screen_descriptor,
54
55            fonts_manager,
56            render_manager,
57            tool_manager: RadiantToolManager::new(0u32, Box::new(default_tool)),
58            interaction_manager: RadiantInteractionManager::new(),
59            texture_manager,
60        }
61    }
62
63    pub fn add(&mut self, mut node: N) {
64        node.attach(&self.screen_descriptor);
65        self.document_mut().add(node);
66    }
67
68    pub fn resize(&mut self, new_size: [u32; 2]) {
69        if new_size[0] > 0 && new_size[1] > 0 {
70            self.screen_descriptor.size_in_pixels = new_size;
71            self.render_manager.resize(new_size);
72        }
73    }
74
75    pub fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
76        self.fonts_manager
77            .begin_frame(self.screen_descriptor.pixels_per_point, 1024);
78        if let Some(font_image_delta) = self.fonts_manager.font_image_delta() {
79            self.texture_manager
80                .0
81                .write()
82                .set(TextureId::default(), font_image_delta);
83        }
84
85        let delta = self.texture_manager.0.write().take_delta();
86        self.render_manager.update_textures(delta);
87
88        let primitives = self.get_primitives(false);
89        self.render_manager
90            .render(primitives, &self.screen_descriptor, false)
91    }
92
93    pub async fn select(&mut self, mouse_position: [f32; 2]) -> u64 {
94        let primitives = self.get_primitives(true);
95        self.render_manager
96            .render_offscreen(primitives, &self.screen_descriptor, true, mouse_position)
97            .await
98            .unwrap()
99    }
100
101    fn get_primitives(&mut self, selection: bool) -> Vec<ClippedPrimitive> {
102        let mut primitives = self.document.write().unwrap().tessellate(
103            selection,
104            &self.screen_descriptor,
105            &self.fonts_manager,
106        );
107
108        let mut p2 = self.interaction_manager.tessellate(
109            selection,
110            &self.screen_descriptor,
111            &self.fonts_manager,
112        );
113        primitives.append(&mut p2);
114
115        primitives
116    }
117}
118
119impl<M: From<RadiantSceneMessage> + TryInto<RadiantSceneMessage>, N: RadiantNode>
120    RadiantScene<M, N>
121{
122    pub fn handle_message(
123        &mut self,
124        message: RadiantSceneMessage,
125    ) -> Option<RadiantSceneResponse<M, N>> {
126        match message {
127            RadiantSceneMessage::AddArtboard {} => {
128                self.document_mut().add_artboard();
129            }
130            RadiantSceneMessage::SelectArtboard { id } => {
131                self.document_mut().set_active_artboard(id);
132            }
133            RadiantSceneMessage::SelectNode { id } => {
134                self.document_mut().select(id);
135                if let Some(id) = id {
136                    if !self.interaction_manager.is_interaction(id) {
137                        if let Some(node) = self.document.write().unwrap().get_node(id) {
138                            self.interaction_manager
139                                .enable_interactions(node, &self.screen_descriptor);
140                            return Some(RadiantSceneResponse::Selected { node: node.clone() });
141                        } else {
142                            self.interaction_manager.disable_interactions();
143                        }
144                    }
145                } else {
146                    self.interaction_manager.disable_interactions();
147                }
148            }
149            RadiantSceneMessage::TransformNode {
150                id,
151                position,
152                scale,
153            } => {
154                if self.interaction_manager.is_interaction(id) {
155                    if let Some(message) =
156                        self.interaction_manager.handle_interaction(message.into())
157                    {
158                        return Some(RadiantSceneResponse::Message { message });
159                    }
160                } else if let Some(node) = self.document.write().unwrap().get_node_mut(id) {
161                    if let Some(component) = node.get_component_mut::<TransformComponent>() {
162                        component.transform_xy(&position);
163                        component.transform_scale(&scale);
164
165                        let response = RadiantSceneResponse::TransformUpdated {
166                            id,
167                            position: component.get_xy(),
168                            scale: component.get_scale(),
169                        };
170
171                        node.set_needs_tessellation();
172                        self.interaction_manager
173                            .update_interactions(node, &self.screen_descriptor);
174
175                        return Some(response);
176                    }
177                }
178            }
179            RadiantSceneMessage::SetTransform {
180                id,
181                position,
182                scale,
183            } => {
184                if let Some(node) = self.document.write().unwrap().get_node_mut(id) {
185                    if let Some(component) = node.get_component_mut::<TransformComponent>() {
186                        component.set_xy(&position);
187                        component.set_scale(&scale);
188                        node.set_needs_tessellation();
189
190                        self.interaction_manager
191                            .update_interactions(node, &self.screen_descriptor);
192                    }
193                }
194            }
195            RadiantSceneMessage::SetFillColor { id, fill_color } => {
196                if let Some(node) = self.document_mut().get_node_mut(id) {
197                    if let Some(component) = node.get_component_mut::<ColorComponent>() {
198                        component.set_fill_color(fill_color);
199                        node.set_needs_tessellation();
200                    }
201                }
202            }
203            RadiantSceneMessage::SetStrokeColor { id, stroke_color } => {
204                if let Some(node) = self.document_mut().get_node_mut(id) {
205                    if let Some(component) = node.get_component_mut::<ColorComponent>() {
206                        component.set_stroke_color(stroke_color);
207                        node.set_needs_tessellation();
208                    }
209                }
210            }
211            RadiantSceneMessage::SelectTool { id } => {
212                self.tool_manager.activate_tool(id);
213            }
214        }
215        None
216    }
217}