1use super::composition_object_impls::composition_object_impls;
17use super::generated::{
18 AmbientLightHooks, AmbientLightProps, CompositionLightHooks, CompositionLightProps, DistantLightHooks,
19 DistantLightProps, PointLightHooks, PointLightProps, ServerAmbientLightProps, ServerDistantLightProps,
20 ServerPointLightProps, ServerSpotLightProps, SpotLightHooks, SpotLightProps, VisualUnorderedCollectionHooks,
21 VisualUnorderedCollectionProps,
22};
23use super::server::{
24 IServerObject, ServerAmbientLight, ServerCompositor, ServerDistantLight, ServerObjectId, ServerPointLight,
25 ServerSpotLight, ServerVisualUnorderedCollection,
26};
27use super::{CompositionObject, CompositionVisual, Compositor, ICompositionObject};
28use crate::media::Color;
29use crate::Vector3D;
30use std::cell::RefCell;
31use std::ops::Deref;
32use std::rc::{Rc, Weak};
33
34pub struct VisualUnorderedCollection {
40 this: Weak<VisualUnorderedCollection>,
41 object: CompositionObject,
42 props: VisualUnorderedCollectionProps<CompositionVisual>,
43}
44
45impl VisualUnorderedCollection {
46 pub(crate) fn new(compositor: &Rc<Compositor>) -> Rc<VisualUnorderedCollection> {
47 let server =
48 compositor.create_server_object(|compositor, _| ServerVisualUnorderedCollection::new(compositor));
49 let collection = Rc::new_cyclic(|this: &Weak<VisualUnorderedCollection>| VisualUnorderedCollection {
50 this: this.clone(),
51 object: CompositionObject::new(compositor, Some(server)),
52 props: VisualUnorderedCollectionProps::new(),
53 });
54 collection.props.initialize_defaults(&*collection);
55 collection
56 }
57
58 pub fn server(&self) -> ServerObjectId {
60 self.object.required_server()
61 }
62
63 pub fn items(&self) -> Vec<Rc<CompositionVisual>> {
66 self.props.items()
67 }
68
69 pub fn add(&self, visual: Rc<CompositionVisual>) {
72 if !self.props.contains(&visual) {
73 self.props.add(self, visual);
74 }
75 }
76
77 pub fn remove(&self, visual: &Rc<CompositionVisual>) -> bool {
80 self.props.remove(self, visual)
81 }
82
83 pub fn remove_all(&self) {
85 self.props.clear(self);
86 }
87
88 pub fn count(&self) -> usize {
90 self.props.count()
91 }
92
93 pub fn contains(&self, visual: &Rc<CompositionVisual>) -> bool {
95 self.props.contains(visual)
96 }
97
98 pub fn is_disposed(&self) -> bool {
99 self.object.is_disposed()
100 }
101
102 pub fn dispose(&self) {
103 self.object.dispose();
104 }
105}
106
107impl VisualUnorderedCollectionHooks<CompositionVisual> for VisualUnorderedCollection {}
108
109composition_object_impls!(
110 VisualUnorderedCollection, "VisualUnorderedCollection",
111 serialize: |this, writer| this.props.serialize_changes_core(this, writer),
112 start_animation: |_this, _name, _animation, _final_value| false,
113 composition_property: |_this, _name| None,
114);
115
116pub(crate) enum CompositionLightKind {
120 Ambient(AmbientLightProps),
121 Distant(DistantLightProps),
122 Point(PointLightProps),
123 Spot(SpotLightProps),
124}
125
126pub struct CompositionLight {
136 this: Weak<CompositionLight>,
137 object: CompositionObject,
138 kind: CompositionLightKind,
139 targets: Rc<VisualUnorderedCollection>,
140 exclusions: Rc<VisualUnorderedCollection>,
141 xaml_binding: RefCell<(Option<String>, Option<Rc<CompositionVisual>>, bool)>,
145}
146
147impl CompositionLight {
148 fn create(
149 compositor: &Rc<Compositor>,
150 kind: CompositionLightKind,
151 server: impl FnOnce(&Rc<ServerCompositor>) -> Rc<dyn IServerObject> + Send + 'static,
152 ) -> Rc<CompositionLight> {
153 let targets = VisualUnorderedCollection::new(compositor);
155 let exclusions = VisualUnorderedCollection::new(compositor);
156 let server = compositor.create_server_object(move |compositor, _| server(compositor));
157 let light = Rc::new_cyclic(|this: &Weak<CompositionLight>| CompositionLight {
158 this: this.clone(),
159 object: CompositionObject::new(compositor, Some(server)),
160 kind,
161 targets,
162 exclusions,
163 xaml_binding: RefCell::new((None, None, false)),
164 });
165 match &light.kind {
166 CompositionLightKind::Ambient(props) => props.initialize_defaults(&*light),
167 CompositionLightKind::Distant(props) => props.initialize_defaults(&*light),
168 CompositionLightKind::Point(props) => props.initialize_defaults(&*light),
169 CompositionLightKind::Spot(props) => props.initialize_defaults(&*light),
170 }
171 let targets: Rc<dyn ICompositionObject> = light.targets.clone();
172 light.light_props().set_targets(&*light, Some(targets));
173 let exclusions: Rc<dyn ICompositionObject> = light.exclusions.clone();
174 light.light_props().set_exclusions_from_targets(&*light, Some(exclusions));
175 light
176 }
177
178 pub fn light_props(&self) -> &CompositionLightProps {
180 match &self.kind {
181 CompositionLightKind::Ambient(props) => props.base(),
182 CompositionLightKind::Distant(props) => props.base(),
183 CompositionLightKind::Point(props) => props.base(),
184 CompositionLightKind::Spot(props) => props.base(),
185 }
186 }
187
188 pub fn compositor(&self) -> &Rc<Compositor> {
189 self.object.compositor()
190 }
191
192 pub fn object(&self) -> &CompositionObject {
194 &self.object
195 }
196
197 pub fn server(&self) -> ServerObjectId {
199 self.object.required_server()
200 }
201
202 pub fn is_disposed(&self) -> bool {
203 self.object.is_disposed()
204 }
205
206 pub fn dispose(&self) {
209 self.object.dispose();
210 self.targets.dispose();
211 self.exclusions.dispose();
212 }
213
214 pub fn type_name(&self) -> &'static str {
216 match &self.kind {
217 CompositionLightKind::Ambient(_) => "AmbientLight",
218 CompositionLightKind::Distant(_) => "DistantLight",
219 CompositionLightKind::Point(_) => "PointLight",
220 CompositionLightKind::Spot(_) => "SpotLight",
221 }
222 }
223
224 pub fn targets(&self) -> &Rc<VisualUnorderedCollection> {
226 &self.targets
227 }
228
229 pub fn exclusions_from_targets(&self) -> &Rc<VisualUnorderedCollection> {
232 &self.exclusions
233 }
234
235 pub fn set_xaml_binding(&self, id: Option<String>, scope: Option<Rc<CompositionVisual>>) {
241 {
242 let mut binding = self.xaml_binding.borrow_mut();
243 let same_scope = match (&binding.1, &scope) {
244 (Some(a), Some(b)) => Rc::ptr_eq(a, b),
245 (None, None) => true,
246 _ => false,
247 };
248 if binding.0 == id && same_scope {
249 return;
250 }
251 *binding = (id, scope, true);
252 }
253 self.object
254 .register_for_serialization(|| self.this.upgrade().map(|this| this as Rc<dyn crate::rendering::composition::ICompositorSerializable>));
255 }
256
257 pub fn xaml_id(&self) -> Option<String> {
259 self.xaml_binding.borrow().0.clone()
260 }
261
262 fn serialize_xaml_binding(&self, writer: &mut crate::rendering::composition::transport::BatchStreamWriter<'_>) {
264 let mut binding = self.xaml_binding.borrow_mut();
265 let changes = binding.2.then(|| crate::rendering::composition::server::XamlLightChanges {
266 id: binding.0.clone(),
267 scope: binding.1.as_ref().and_then(|scope| scope.object().server()),
268 });
269 binding.2 = false;
270 writer.write_value(changes);
271 }
272
273 pub fn is_enabled(&self) -> bool {
276 self.light_props().is_enabled()
277 }
278
279 pub fn set_is_enabled(&self, value: bool) {
280 self.light_props().set_is_enabled(self, value)
281 }
282}
283
284impl CompositionLightHooks for CompositionLight {}
285
286impl AmbientLightHooks for CompositionLight {}
287
288impl DistantLightHooks for CompositionLight {}
289
290impl PointLightHooks for CompositionLight {}
291
292impl SpotLightHooks for CompositionLight {}
293
294composition_object_impls!(
295 CompositionLight, "CompositionLight",
296 serialize: |this, writer| {
297 match &this.kind {
298 CompositionLightKind::Ambient(props) => props.serialize_changes_core(this, writer),
299 CompositionLightKind::Distant(props) => props.serialize_changes_core(this, writer),
300 CompositionLightKind::Point(props) => props.serialize_changes_core(this, writer),
301 CompositionLightKind::Spot(props) => props.serialize_changes_core(this, writer),
302 }
303 this.serialize_xaml_binding(writer);
304 },
305 start_animation: |this, name, animation, final_value| match &this.kind {
306 CompositionLightKind::Ambient(props) => props.start_animation(this, name, animation, final_value),
307 CompositionLightKind::Distant(props) => props.start_animation(this, name, animation, final_value),
308 CompositionLightKind::Point(props) => props.start_animation(this, name, animation, final_value),
309 CompositionLightKind::Spot(props) => props.start_animation(this, name, animation, final_value),
310 },
311 composition_property: |this, name| match &this.kind {
312 CompositionLightKind::Ambient(_) => ServerAmbientLightProps::get_composition_property(name),
313 CompositionLightKind::Distant(_) => ServerDistantLightProps::get_composition_property(name),
314 CompositionLightKind::Point(_) => ServerPointLightProps::get_composition_property(name),
315 CompositionLightKind::Spot(_) => ServerSpotLightProps::get_composition_property(name),
316 },
317);
318
319fn as_visual(object: Option<Rc<dyn ICompositionObject>>) -> Option<Rc<CompositionVisual>> {
321 object.and_then(|visual| visual.into_any_rc().downcast::<CompositionVisual>().ok())
322}
323
324fn as_object(visual: Option<Rc<CompositionVisual>>) -> Option<Rc<dyn ICompositionObject>> {
326 visual.map(|visual| visual as Rc<dyn ICompositionObject>)
327}
328
329macro_rules! light_handle {
332 ($(#[$meta:meta])* $name:ident, $kind:ident, $props:ident) => {
333 $(#[$meta])*
334 #[derive(Clone)]
335 pub struct $name(Rc<CompositionLight>);
336
337 impl Deref for $name {
338 type Target = Rc<CompositionLight>;
339
340 fn deref(&self) -> &Rc<CompositionLight> {
341 &self.0
342 }
343 }
344
345 impl $name {
346 pub fn from_light(light: &Rc<CompositionLight>) -> Option<$name> {
348 matches!(light.kind, CompositionLightKind::$kind(_)).then(|| $name(light.clone()))
349 }
350
351 pub fn props(&self) -> &$props {
353 match &self.0.kind {
354 CompositionLightKind::$kind(props) => props,
355 _ => unreachable!("a light handle wraps a light of its class"),
356 }
357 }
358 }
359 };
360}
361
362light_handle!(
363 AmbientLight,
367 Ambient,
368 AmbientLightProps
369);
370
371impl AmbientLight {
372 pub(crate) fn new(compositor: &Rc<Compositor>) -> AmbientLight {
373 AmbientLight(CompositionLight::create(
374 compositor,
375 CompositionLightKind::Ambient(AmbientLightProps::new()),
376 |c| ServerAmbientLight::new(c),
377 ))
378 }
379
380 pub fn color(&self) -> Color {
382 self.props().color()
383 }
384
385 pub fn set_color(&self, value: Color) {
386 self.props().set_color(&*self.0, value)
387 }
388
389 pub fn intensity(&self) -> f32 {
391 self.props().intensity()
392 }
393
394 pub fn set_intensity(&self, value: f32) {
395 self.props().set_intensity(&*self.0, value)
396 }
397}
398
399light_handle!(
400 DistantLight,
405 Distant,
406 DistantLightProps
407);
408
409impl DistantLight {
410 pub(crate) fn new(compositor: &Rc<Compositor>) -> DistantLight {
411 DistantLight(CompositionLight::create(
412 compositor,
413 CompositionLightKind::Distant(DistantLightProps::new()),
414 |c| ServerDistantLight::new(c),
415 ))
416 }
417
418 pub fn color(&self) -> Color {
420 self.props().color()
421 }
422
423 pub fn set_color(&self, value: Color) {
424 self.props().set_color(&*self.0, value)
425 }
426
427 pub fn coordinate_space(&self) -> Option<Rc<CompositionVisual>> {
430 as_visual(self.props().coordinate_space())
431 }
432
433 pub fn set_coordinate_space(&self, value: Option<Rc<CompositionVisual>>) {
434 self.props().set_coordinate_space(&*self.0, as_object(value))
435 }
436
437 pub fn direction(&self) -> Vector3D {
440 self.props().direction()
441 }
442
443 pub fn set_direction(&self, value: Vector3D) {
444 self.props().set_direction(&*self.0, value)
445 }
446
447 pub fn intensity(&self) -> f32 {
449 self.props().intensity()
450 }
451
452 pub fn set_intensity(&self, value: f32) {
453 self.props().set_intensity(&*self.0, value)
454 }
455}
456
457light_handle!(
458 PointLight,
464 Point,
465 PointLightProps
466);
467
468impl PointLight {
469 pub(crate) fn new(compositor: &Rc<Compositor>) -> PointLight {
470 PointLight(CompositionLight::create(
471 compositor,
472 CompositionLightKind::Point(PointLightProps::new()),
473 |c| ServerPointLight::new(c),
474 ))
475 }
476
477 pub fn color(&self) -> Color {
479 self.props().color()
480 }
481
482 pub fn set_color(&self, value: Color) {
483 self.props().set_color(&*self.0, value)
484 }
485
486 pub fn constant_attenuation(&self) -> f32 {
488 self.props().constant_attenuation()
489 }
490
491 pub fn set_constant_attenuation(&self, value: f32) {
492 self.props().set_constant_attenuation(&*self.0, value)
493 }
494
495 pub fn linear_attenuation(&self) -> f32 {
497 self.props().linear_attenuation()
498 }
499
500 pub fn set_linear_attenuation(&self, value: f32) {
501 self.props().set_linear_attenuation(&*self.0, value)
502 }
503
504 pub fn quadratic_attenuation(&self) -> f32 {
507 self.props().quadratic_attenuation()
508 }
509
510 pub fn set_quadratic_attenuation(&self, value: f32) {
511 self.props().set_quadratic_attenuation(&*self.0, value)
512 }
513
514 pub fn coordinate_space(&self) -> Option<Rc<CompositionVisual>> {
517 as_visual(self.props().coordinate_space())
518 }
519
520 pub fn set_coordinate_space(&self, value: Option<Rc<CompositionVisual>>) {
521 self.props().set_coordinate_space(&*self.0, as_object(value))
522 }
523
524 pub fn offset(&self) -> Vector3D {
527 self.props().offset()
528 }
529
530 pub fn set_offset(&self, value: Vector3D) {
531 self.props().set_offset(&*self.0, value)
532 }
533
534 pub fn intensity(&self) -> f32 {
536 self.props().intensity()
537 }
538
539 pub fn set_intensity(&self, value: f32) {
540 self.props().set_intensity(&*self.0, value)
541 }
542
543 pub fn min_attenuation_cutoff(&self) -> f32 {
545 self.props().min_attenuation_cutoff()
546 }
547
548 pub fn set_min_attenuation_cutoff(&self, value: f32) {
549 self.props().set_min_attenuation_cutoff(&*self.0, value)
550 }
551
552 pub fn max_attenuation_cutoff(&self) -> f32 {
555 self.props().max_attenuation_cutoff()
556 }
557
558 pub fn set_max_attenuation_cutoff(&self, value: f32) {
559 self.props().set_max_attenuation_cutoff(&*self.0, value)
560 }
561}
562
563light_handle!(
564 SpotLight,
576 Spot,
577 SpotLightProps
578);
579
580impl SpotLight {
581 pub(crate) fn new(compositor: &Rc<Compositor>) -> SpotLight {
582 SpotLight(CompositionLight::create(
583 compositor,
584 CompositionLightKind::Spot(SpotLightProps::new()),
585 |c| ServerSpotLight::new(c),
586 ))
587 }
588
589 pub fn constant_attenuation(&self) -> f32 {
591 self.props().constant_attenuation()
592 }
593
594 pub fn set_constant_attenuation(&self, value: f32) {
595 self.props().set_constant_attenuation(&*self.0, value)
596 }
597
598 pub fn linear_attenuation(&self) -> f32 {
600 self.props().linear_attenuation()
601 }
602
603 pub fn set_linear_attenuation(&self, value: f32) {
604 self.props().set_linear_attenuation(&*self.0, value)
605 }
606
607 pub fn quadratic_attenuation(&self) -> f32 {
610 self.props().quadratic_attenuation()
611 }
612
613 pub fn set_quadratic_attenuation(&self, value: f32) {
614 self.props().set_quadratic_attenuation(&*self.0, value)
615 }
616
617 pub fn coordinate_space(&self) -> Option<Rc<CompositionVisual>> {
620 as_visual(self.props().coordinate_space())
621 }
622
623 pub fn set_coordinate_space(&self, value: Option<Rc<CompositionVisual>>) {
624 self.props().set_coordinate_space(&*self.0, as_object(value))
625 }
626
627 pub fn direction(&self) -> Vector3D {
629 self.props().direction()
630 }
631
632 pub fn set_direction(&self, value: Vector3D) {
633 self.props().set_direction(&*self.0, value)
634 }
635
636 pub fn inner_cone_angle(&self) -> f32 {
639 self.props().inner_cone_angle()
640 }
641
642 pub fn set_inner_cone_angle(&self, value: f32) {
643 self.props().set_inner_cone_angle(&*self.0, value)
644 }
645
646 pub fn inner_cone_angle_in_degrees(&self) -> f32 {
649 self.inner_cone_angle().to_degrees()
650 }
651
652 pub fn set_inner_cone_angle_in_degrees(&self, value: f32) {
653 self.set_inner_cone_angle(value.to_radians())
654 }
655
656 pub fn inner_cone_color(&self) -> Color {
658 self.props().inner_cone_color()
659 }
660
661 pub fn set_inner_cone_color(&self, value: Color) {
662 self.props().set_inner_cone_color(&*self.0, value)
663 }
664
665 pub fn inner_cone_intensity(&self) -> f32 {
667 self.props().inner_cone_intensity()
668 }
669
670 pub fn set_inner_cone_intensity(&self, value: f32) {
671 self.props().set_inner_cone_intensity(&*self.0, value)
672 }
673
674 pub fn outer_cone_angle(&self) -> f32 {
677 self.props().outer_cone_angle()
678 }
679
680 pub fn set_outer_cone_angle(&self, value: f32) {
681 self.props().set_outer_cone_angle(&*self.0, value)
682 }
683
684 pub fn outer_cone_angle_in_degrees(&self) -> f32 {
687 self.outer_cone_angle().to_degrees()
688 }
689
690 pub fn set_outer_cone_angle_in_degrees(&self, value: f32) {
691 self.set_outer_cone_angle(value.to_radians())
692 }
693
694 pub fn outer_cone_color(&self) -> Color {
697 self.props().outer_cone_color()
698 }
699
700 pub fn set_outer_cone_color(&self, value: Color) {
701 self.props().set_outer_cone_color(&*self.0, value)
702 }
703
704 pub fn outer_cone_intensity(&self) -> f32 {
707 self.props().outer_cone_intensity()
708 }
709
710 pub fn set_outer_cone_intensity(&self, value: f32) {
711 self.props().set_outer_cone_intensity(&*self.0, value)
712 }
713
714 pub fn offset(&self) -> Vector3D {
717 self.props().offset()
718 }
719
720 pub fn set_offset(&self, value: Vector3D) {
721 self.props().set_offset(&*self.0, value)
722 }
723
724 pub fn min_attenuation_cutoff(&self) -> f32 {
726 self.props().min_attenuation_cutoff()
727 }
728
729 pub fn set_min_attenuation_cutoff(&self, value: f32) {
730 self.props().set_min_attenuation_cutoff(&*self.0, value)
731 }
732
733 pub fn max_attenuation_cutoff(&self) -> f32 {
736 self.props().max_attenuation_cutoff()
737 }
738
739 pub fn set_max_attenuation_cutoff(&self, value: f32) {
740 self.props().set_max_attenuation_cutoff(&*self.0, value)
741 }
742}
743
744impl Compositor {
745 pub fn create_ambient_light(&self) -> AmbientLight {
747 AmbientLight::new(&self.this_handle())
748 }
749
750 pub fn create_distant_light(&self) -> DistantLight {
752 DistantLight::new(&self.this_handle())
753 }
754
755 pub fn create_point_light(&self) -> PointLight {
757 PointLight::new(&self.this_handle())
758 }
759
760 pub fn create_spot_light(&self) -> SpotLight {
762 SpotLight::new(&self.this_handle())
763 }
764}