1use std::hash::Hash;
4
5use crate::{
6 node::{NodeResult, NodeType},
7 spatial::{SpatialRefAspect, Transform},
8};
9use stardust_xr::values::*;
10
11pub use crate::protocol::drawable::*;
12
13impl Lines {
14 pub fn create(
15 spatial_parent: &impl SpatialRefAspect,
16 transform: Transform,
17 lines: &[Line],
18 ) -> NodeResult<Self> {
19 let client = spatial_parent.client();
20 create_lines(
21 client,
22 client.generate_id(),
23 spatial_parent,
24 transform,
25 lines,
26 )
27 }
28}
29impl Default for LinePoint {
30 fn default() -> Self {
31 Self {
32 point: [0.0; 3].into(),
33 thickness: 0.01,
34 color: color::rgba_linear!(1.0, 1.0, 1.0, 1.0),
35 }
36 }
37}
38impl Copy for LinePoint {}
39impl Hash for LinePoint {
40 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
41 self.color.c.r.to_bits().hash(state);
42 self.color.c.g.to_bits().hash(state);
43 self.color.c.b.to_bits().hash(state);
44 self.color.a.to_bits().hash(state);
45
46 self.point.x.to_bits().hash(state);
47 self.point.y.to_bits().hash(state);
48 self.point.z.to_bits().hash(state);
49
50 self.thickness.to_bits().hash(state);
51 }
52}
53impl Default for Line {
54 fn default() -> Self {
55 Self {
56 points: Default::default(),
57 cyclic: Default::default(),
58 }
59 }
60}
61impl Hash for Line {
62 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
63 self.cyclic.hash(state);
64 self.points.hash(state);
65 }
66}
67
68impl Model {
69 pub fn create(
70 spatial_parent: &impl SpatialRefAspect,
71 transform: Transform,
72 model: &ResourceID,
73 ) -> NodeResult<Self> {
74 let client = spatial_parent.client();
75 load_model(
76 client,
77 client.generate_id(),
78 spatial_parent,
79 transform,
80 model,
81 )
82 }
83 pub fn part(&self, relative_path: &str) -> NodeResult<ModelPart> {
84 let client = self.client();
85 self.bind_model_part(client.generate_id(), relative_path)
86 }
87}
88impl Text {
89 pub fn create(
90 spatial_parent: &impl SpatialRefAspect,
91 transform: Transform,
92 text: &str,
93 style: TextStyle,
94 ) -> NodeResult<Self> {
95 let client = spatial_parent.client();
96 create_text(
97 client,
98 client.generate_id(),
99 spatial_parent,
100 transform,
101 text,
102 style,
103 )
104 }
105}
106impl Default for TextStyle {
107 fn default() -> Self {
108 Self {
109 character_height: 0.01,
110 color: color::rgba_linear!(1.0, 1.0, 1.0, 1.0),
111 font: Default::default(),
112 text_align_x: XAlign::Left,
113 text_align_y: YAlign::Top,
114 bounds: Default::default(),
115 }
116 }
117}
118impl Hash for TextBounds {
119 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
120 self.bounds.x.to_bits().hash(state);
121 self.bounds.y.to_bits().hash(state);
122
123 self.fit.hash(state);
124 self.anchor_align_x.hash(state);
125 self.anchor_align_y.hash(state);
126 }
127}
128impl Hash for TextStyle {
129 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
130 self.character_height.to_bits().hash(state);
131
132 self.color.c.r.to_bits().hash(state);
133 self.color.c.g.to_bits().hash(state);
134 self.color.c.b.to_bits().hash(state);
135 self.color.a.to_bits().hash(state);
136
137 self.font.hash(state);
138 self.text_align_x.hash(state);
139 self.text_align_y.hash(state);
140 self.bounds.hash(state);
141 }
142}
143
144#[tokio::test]
145async fn fusion_lines() {
146 let mut client = crate::Client::connect().await.unwrap();
147
148 let points = vec![
149 LinePoint {
150 point: Vector3 {
151 x: 1.0,
152 y: 0.0,
153 z: 0.0,
154 },
155 thickness: 0.0025,
156 ..Default::default()
157 },
158 LinePoint {
159 thickness: 0.0025,
160 ..Default::default()
161 },
162 LinePoint {
163 point: Vector3 {
164 x: 0.0,
165 y: 1.0,
166 z: 0.0,
167 },
168 thickness: 0.0025,
169 ..Default::default()
170 },
171 ];
172 let line = Line {
173 points,
174 cyclic: true,
175 };
176 let _lines = Lines::create(client.get_root(), Transform::none(), &[line]).unwrap();
177
178 client.flush().await.unwrap();
179 tokio::time::sleep(core::time::Duration::from_secs(60)).await;
180}
181
182#[tokio::test]
183async fn fusion_model() {
184 let mut client = crate::Client::connect().await.unwrap();
185
186 let gyro_resource = ResourceID::new_namespaced("fusion", "gyro");
187 let gyro_model = Model::create(client.get_root(), Transform::none(), &gyro_resource).unwrap();
188 gyro_model
189 .part("Gem")
190 .unwrap()
191 .set_material_parameter(
192 "color",
193 MaterialParameter::Color(color::rgba_linear!(0.0, 1.0, 0.5, 0.75)),
194 )
195 .unwrap();
196
197 let spike_resource = ResourceID::new_namespaced("fusion", "cursor_spike");
198 let spike_model = Model::create(
199 client.get_root(),
200 Transform::from_translation_scale([0.0, 0.1, 0.0], [0.1; 3]),
201 &spike_resource,
202 )
203 .unwrap();
204 spike_model
205 .part("Cone")
206 .unwrap()
207 .apply_holdout_material()
208 .unwrap();
209
210 client.flush().await.unwrap();
211 tokio::time::sleep(core::time::Duration::from_secs(60)).await;
212}
213#[tokio::test]
214async fn fusion_text() {
215 let mut client = crate::Client::connect().await.unwrap();
216
217 let style: TextStyle = TextStyle {
218 font: Some(stardust_xr::values::ResourceID::new_namespaced(
219 "fusion",
220 "common_case",
221 )),
222 ..Default::default()
223 };
224 let text = Text::create(client.get_root(), Transform::none(), "Test Text", style).unwrap();
225 text.set_character_height(0.05).unwrap();
226 text.set_text("Test Text: Changed").unwrap();
227
228 client.flush().await.unwrap();
229 tokio::time::sleep(core::time::Duration::from_secs(60)).await;
230}
231
232#[tokio::test]
233async fn fusion_sky() {
234 let client = crate::Client::connect().await.expect("Couldn't connect");
235 client
236 .setup_resources(&[&crate::project_local_resources!("res")])
237 .unwrap();
238 let client_handle = client.handle();
239 let _event_loop = client.async_event_loop();
240 let sky_resource = stardust_xr::values::ResourceID::new_namespaced("fusion", "sky");
241
242 set_sky_light(&client_handle, Some(&sky_resource)).unwrap();
243 set_sky_tex(&client_handle, Some(&sky_resource)).unwrap();
244
245 tokio::time::sleep(core::time::Duration::from_secs(5)).await;
246
247 set_sky_light(&client_handle, None).unwrap();
248 set_sky_tex(&client_handle, None).unwrap();
249 tokio::time::sleep(core::time::Duration::from_secs(1)).await;
250}