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 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}