lgui_core/core/scene/render/
scene.rs1use super::{memory::estimate_scene_commands_bytes, primitive::*, projection::project_command, *};
2
3#[derive(Clone, Debug, Default)]
4pub struct Scene {
5 pub(super) commands: Arc<Vec<ScenePrimitive>>,
6}
7
8impl Scene {
9 pub fn new() -> Self {
10 Self {
11 commands: Arc::new(Vec::new()),
12 }
13 }
14
15 pub fn push(&mut self, command: ScenePrimitive) {
16 Arc::make_mut(&mut self.commands).push(command);
17 }
18
19 pub fn commands(&self) -> &[ScenePrimitive] {
20 self.commands.as_slice()
21 }
22
23 #[doc(hidden)]
24 pub fn shares_command_storage_with(&self, other: &Self) -> bool {
25 Arc::ptr_eq(&self.commands, &other.commands)
26 }
27
28 pub fn image_requests(&self) -> Vec<ImageRequest> {
29 let mut requests = Vec::new();
30 collect_image_requests(self.commands(), &mut requests);
31 requests
32 }
33
34 pub fn estimated_bytes(&self) -> usize {
35 estimate_scene_commands_bytes(self.commands())
36 }
37
38 pub(super) fn move_popup_commands_to_end(&mut self) {
39 let commands = Arc::make_mut(&mut self.commands);
40 let (popup, regular): (Vec<_>, Vec<_>) = std::mem::take(commands)
41 .into_iter()
42 .partition(|command| command.phase() == RenderPhase::Popup);
43 *commands = regular;
44 commands.extend(popup);
45 }
46
47 pub(crate) fn replace_range(
48 &mut self,
49 range: std::ops::Range<usize>,
50 commands: impl IntoIterator<Item = ScenePrimitive>,
51 ) {
52 Arc::make_mut(&mut self.commands).splice(range, commands);
53 }
54
55 pub(crate) fn replace_all(&mut self, commands: Vec<ScenePrimitive>) {
56 self.commands = Arc::new(commands);
57 }
58
59 pub(crate) fn patch_compositing_layer_spec(
60 &mut self,
61 id: &UiId,
62 spec: CompositingLayerSpec,
63 ) -> bool {
64 let commands = Arc::make_mut(&mut self.commands);
65 patch_compositing_layer_spec(commands.as_mut_slice(), id, spec)
66 }
67
68 pub fn bounds(&self) -> Option<UiRect> {
69 self.commands()
70 .iter()
71 .map(ScenePrimitive::rect)
72 .reduce(UiRect::union)
73 }
74
75 pub fn project_to_physical(&self, scale: UiScale) -> Self {
76 if scale.is_identity() {
77 return self.clone();
78 }
79 Self {
80 commands: Arc::new(
81 self.commands
82 .iter()
83 .map(|command| project_command(command, scale))
84 .collect(),
85 ),
86 }
87 }
88}
89
90fn collect_image_requests(commands: &[ScenePrimitive], requests: &mut Vec<ImageRequest>) {
91 for command in commands {
92 match command {
93 ScenePrimitive::Image { request, .. } => requests.push(request.clone()),
94 ScenePrimitive::CompositingLayer { commands, .. }
95 | ScenePrimitive::StaticLayer { commands, .. }
96 | ScenePrimitive::ScrollRaster { commands, .. }
97 | ScenePrimitive::Clip { commands, .. }
98 | ScenePrimitive::ClipPath { commands, .. } => {
99 collect_image_requests(commands, requests);
100 }
101 _ => {}
102 }
103 }
104}
105
106pub(crate) fn patch_compositing_layer_spec(
107 commands: &mut [ScenePrimitive],
108 source: &UiId,
109 next_spec: CompositingLayerSpec,
110) -> bool {
111 for command in commands {
112 let nested = match command {
113 ScenePrimitive::CompositingLayer {
114 id, spec, commands, ..
115 } => {
116 if id == source {
117 *spec = next_spec;
118 return true;
119 }
120 Some(commands)
121 }
122 ScenePrimitive::StaticLayer { commands, .. }
123 | ScenePrimitive::ScrollRaster { commands, .. }
124 | ScenePrimitive::Clip { commands, .. }
125 | ScenePrimitive::ClipPath { commands, .. } => Some(commands),
126 _ => None,
127 };
128 if nested.is_some_and(|commands| patch_compositing_layer_spec(commands, source, next_spec))
129 {
130 return true;
131 }
132 }
133 false
134}