use bitflags::bitflags;
use crate::rendering::composition::ICompositionObject;
use crate::rendering::composition::ICompositionObjectHost;
use crate::rendering::composition::expressions::ExpressionVariant;
use crate::rendering::composition::server::AsServerRenderResource;
use crate::rendering::composition::server::CompositionProperty;
use crate::rendering::composition::server::CompositionPropertyOf;
use crate::rendering::composition::server::IServerAnimatedPropertyHost;
use crate::rendering::composition::server::IServerObject;
use crate::rendering::composition::server::ServerPropertyValue;
use crate::rendering::composition::server::ServerValueChange;
use crate::rendering::composition::server::props_of;
use crate::rendering::composition::server::read_server_object;
use crate::rendering::composition::transport::BatchStreamReader;
use crate::rendering::composition::transport::BatchStreamWriter;
use crate::rendering::composition::transport::BatchValue;
use crate::rendering::composition::transport::BatchValueReader;
use std::any::Any;
use std::any::TypeId;
use std::cell::Cell;
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::OnceLock;
use std::time::Duration;
bitflags! {
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct CompositionLightChangedFields: u8 {
const TARGETS = 1;
const EXCLUSIONS_FROM_TARGETS = 2;
const IS_ENABLED = 4;
}
}
impl BatchValue for CompositionLightChangedFields {
#[inline]
fn write_to(&self, out: &mut Vec<u8>) {
self.bits().write_to(out);
}
#[inline]
fn read_from(input: &mut BatchValueReader<'_>) -> Self {
CompositionLightChangedFields::from_bits_retain(u8::read_from(input))
}
}
pub trait CompositionLightHooks: ICompositionObjectHost {
fn initialize_defaults_extra(&self) {}
fn validate_targets_change(&self, _old_value: &Option<Rc<dyn ICompositionObject>>, _new_value: &Option<Rc<dyn ICompositionObject>>) {}
fn on_targets_changed(&self) {}
fn on_targets_changing(&self) {}
fn validate_exclusions_from_targets_change(&self, _old_value: &Option<Rc<dyn ICompositionObject>>, _new_value: &Option<Rc<dyn ICompositionObject>>) {}
fn on_exclusions_from_targets_changed(&self) {}
fn on_exclusions_from_targets_changing(&self) {}
fn validate_is_enabled_change(&self, _old_value: bool, _new_value: bool) {}
fn on_is_enabled_changed(&self) {}
fn on_is_enabled_changing(&self) {}
}
pub struct CompositionLightProps {
changed_fields_of_composition_light: Cell<CompositionLightChangedFields>,
targets: RefCell<Option<Rc<dyn ICompositionObject>>>,
exclusions_from_targets: RefCell<Option<Rc<dyn ICompositionObject>>>,
is_enabled: Cell<bool>,
}
impl Default for CompositionLightProps {
fn default() -> Self {
Self::new()
}
}
impl CompositionLightProps {
pub fn new() -> Self {
Self {
changed_fields_of_composition_light: Cell::new(CompositionLightChangedFields::empty()),
targets: RefCell::new(None),
exclusions_from_targets: RefCell::new(None),
is_enabled: Cell::new(Default::default()),
}
}
pub fn initialize_defaults(&self, host: &dyn CompositionLightHooks) {
self.initialize_own_defaults(host);
}
pub fn initialize_own_defaults(&self, host: &dyn CompositionLightHooks) {
CompositionLightHooks::initialize_defaults_extra(host);
self.set_is_enabled(host, true);
}
pub fn targets(&self) -> Option<Rc<dyn ICompositionObject>> {
self.targets.borrow().clone()
}
pub fn set_targets(&self, host: &dyn CompositionLightHooks, value: Option<Rc<dyn ICompositionObject>>) {
let mut changed = false;
let old_value = self.targets.borrow().clone();
if old_value.differs(&value) {
CompositionLightHooks::validate_targets_change(host, &old_value, &value);
CompositionLightHooks::on_targets_changing(host);
changed = true;
*self.targets.borrow_mut() = value.clone();
self.changed_fields_of_composition_light.set(self.changed_fields_of_composition_light.get() | CompositionLightChangedFields::TARGETS);
host.register_for_serialization();
}
*self.targets.borrow_mut() = value;
if changed {
CompositionLightHooks::on_targets_changed(host);
}
}
pub fn exclusions_from_targets(&self) -> Option<Rc<dyn ICompositionObject>> {
self.exclusions_from_targets.borrow().clone()
}
pub fn set_exclusions_from_targets(&self, host: &dyn CompositionLightHooks, value: Option<Rc<dyn ICompositionObject>>) {
let mut changed = false;
let old_value = self.exclusions_from_targets.borrow().clone();
if old_value.differs(&value) {
CompositionLightHooks::validate_exclusions_from_targets_change(host, &old_value, &value);
CompositionLightHooks::on_exclusions_from_targets_changing(host);
changed = true;
*self.exclusions_from_targets.borrow_mut() = value.clone();
self.changed_fields_of_composition_light.set(self.changed_fields_of_composition_light.get() | CompositionLightChangedFields::EXCLUSIONS_FROM_TARGETS);
host.register_for_serialization();
}
*self.exclusions_from_targets.borrow_mut() = value;
if changed {
CompositionLightHooks::on_exclusions_from_targets_changed(host);
}
}
pub fn is_enabled(&self) -> bool {
self.is_enabled.get()
}
pub fn set_is_enabled(&self, host: &dyn CompositionLightHooks, value: bool) {
let mut changed = false;
let old_value = self.is_enabled.get();
if old_value.differs(&value) {
CompositionLightHooks::validate_is_enabled_change(host, old_value, value);
CompositionLightHooks::on_is_enabled_changing(host);
changed = true;
self.is_enabled.set(value);
self.changed_fields_of_composition_light.set(self.changed_fields_of_composition_light.get() | CompositionLightChangedFields::IS_ENABLED);
host.register_for_serialization();
}
self.is_enabled.set(value);
if changed {
CompositionLightHooks::on_is_enabled_changed(host);
}
}
pub fn serialize_changes_core(&self, _host: &dyn CompositionLightHooks, writer: &mut BatchStreamWriter<'_>) {
let changed = self.changed_fields_of_composition_light.get();
writer.write(changed);
if changed.contains(CompositionLightChangedFields::TARGETS) {
writer.write_server_object(self.targets.borrow().clone().map(|o| o.server()));
}
if changed.contains(CompositionLightChangedFields::EXCLUSIONS_FROM_TARGETS) {
writer.write_server_object(self.exclusions_from_targets.borrow().clone().map(|o| o.server()));
}
if changed.contains(CompositionLightChangedFields::IS_ENABLED) {
writer.write(self.is_enabled.get());
}
self.changed_fields_of_composition_light.set(CompositionLightChangedFields::empty());
}
}
pub trait ServerCompositionLightHooks: IServerAnimatedPropertyHost {
fn deserialize_changes_extra(&self, _reader: &mut BatchStreamReader<'_>) {}
fn on_fields_deserialized(&self, _changed: CompositionLightChangedFields) {}
fn on_targets_changed(&self) {}
fn on_targets_changing(&self) {}
fn on_exclusions_from_targets_changed(&self) {}
fn on_exclusions_from_targets_changing(&self) {}
fn on_is_enabled_changed(&self) {}
fn on_is_enabled_changing(&self) {}
}
pub struct ServerCompositionLightProps {
targets: RefCell<Option<Rc<dyn IServerObject>>>,
exclusions_from_targets: RefCell<Option<Rc<dyn IServerObject>>>,
is_enabled: Cell<bool>,
}
impl Default for ServerCompositionLightProps {
fn default() -> Self {
Self::new()
}
}
impl ServerCompositionLightProps {
pub fn new() -> Self {
Self {
targets: RefCell::new(None),
exclusions_from_targets: RefCell::new(None),
is_enabled: Cell::new(Default::default()),
}
}
pub fn find_props(&self, type_id: TypeId) -> Option<&dyn Any> {
if type_id == TypeId::of::<Self>() {
return Some(self);
}
None
}
pub fn id_of_targets_property() -> &'static CompositionPropertyOf<Option<Rc<dyn IServerObject>>> {
static PROPERTY: OnceLock<CompositionPropertyOf<Option<Rc<dyn IServerObject>>>> = OnceLock::new();
PROPERTY.get_or_init(|| {
CompositionProperty::register::<ServerCompositionLightProps, Option<Rc<dyn IServerObject>>>(
"Targets",
"ServerCompositionLight",
|obj| props_of::<ServerCompositionLightProps>(obj).targets.borrow().clone(),
|obj, v| *props_of::<ServerCompositionLightProps>(obj).targets.borrow_mut() = v,
None,
None,
)
})
}
pub fn targets(&self) -> Option<Rc<dyn IServerObject>> {
self.targets.borrow().clone()
}
pub fn set_targets(&self, host: &dyn ServerCompositionLightHooks, value: Option<Rc<dyn IServerObject>>) {
let old_value = self.targets.borrow().clone();
let mut changed = false;
if old_value.differs(&value) {
ServerCompositionLightHooks::on_targets_changing(host);
changed = true;
}
host.set_value(
Self::id_of_targets_property().base(),
ServerValueChange {
equal: old_value.default_equals(&value),
old_resource: old_value.as_server_render_resource(),
new_resource: value.as_server_render_resource(),
assign: &mut || *self.targets.borrow_mut() = value.clone(),
},
);
if changed {
ServerCompositionLightHooks::on_targets_changed(host);
}
}
pub fn id_of_exclusions_from_targets_property() -> &'static CompositionPropertyOf<Option<Rc<dyn IServerObject>>> {
static PROPERTY: OnceLock<CompositionPropertyOf<Option<Rc<dyn IServerObject>>>> = OnceLock::new();
PROPERTY.get_or_init(|| {
CompositionProperty::register::<ServerCompositionLightProps, Option<Rc<dyn IServerObject>>>(
"ExclusionsFromTargets",
"ServerCompositionLight",
|obj| props_of::<ServerCompositionLightProps>(obj).exclusions_from_targets.borrow().clone(),
|obj, v| *props_of::<ServerCompositionLightProps>(obj).exclusions_from_targets.borrow_mut() = v,
None,
None,
)
})
}
pub fn exclusions_from_targets(&self) -> Option<Rc<dyn IServerObject>> {
self.exclusions_from_targets.borrow().clone()
}
pub fn set_exclusions_from_targets(&self, host: &dyn ServerCompositionLightHooks, value: Option<Rc<dyn IServerObject>>) {
let old_value = self.exclusions_from_targets.borrow().clone();
let mut changed = false;
if old_value.differs(&value) {
ServerCompositionLightHooks::on_exclusions_from_targets_changing(host);
changed = true;
}
host.set_value(
Self::id_of_exclusions_from_targets_property().base(),
ServerValueChange {
equal: old_value.default_equals(&value),
old_resource: old_value.as_server_render_resource(),
new_resource: value.as_server_render_resource(),
assign: &mut || *self.exclusions_from_targets.borrow_mut() = value.clone(),
},
);
if changed {
ServerCompositionLightHooks::on_exclusions_from_targets_changed(host);
}
}
pub fn id_of_is_enabled_property() -> &'static CompositionPropertyOf<bool> {
static PROPERTY: OnceLock<CompositionPropertyOf<bool>> = OnceLock::new();
PROPERTY.get_or_init(|| {
CompositionProperty::register::<ServerCompositionLightProps, bool>(
"IsEnabled",
"ServerCompositionLight",
|obj| props_of::<ServerCompositionLightProps>(obj).is_enabled.get(),
|obj, v| props_of::<ServerCompositionLightProps>(obj).is_enabled.set(v),
Some(|obj| ExpressionVariant::create(props_of::<ServerCompositionLightProps>(obj).is_enabled.get())),
None,
)
})
}
pub fn is_enabled(&self) -> bool {
self.is_enabled.get()
}
pub fn set_is_enabled(&self, host: &dyn ServerCompositionLightHooks, value: bool) {
let old_value = self.is_enabled.get();
let mut changed = false;
if old_value.differs(&value) {
ServerCompositionLightHooks::on_is_enabled_changing(host);
changed = true;
}
host.set_value(
Self::id_of_is_enabled_property().base(),
ServerValueChange {
equal: old_value.default_equals(&value),
old_resource: None,
new_resource: None,
assign: &mut || self.is_enabled.set(value),
},
);
if changed {
ServerCompositionLightHooks::on_is_enabled_changed(host);
}
}
pub fn deserialize_changes_core(
&self,
host: &dyn ServerCompositionLightHooks,
reader: &mut BatchStreamReader<'_>,
_committed_at: Duration,
) {
let compositor = host.server_compositor();
ServerCompositionLightHooks::deserialize_changes_extra(host, reader);
let changed = reader.read::<CompositionLightChangedFields>();
if changed.contains(CompositionLightChangedFields::TARGETS) {
let value = read_server_object(reader, compositor.as_ref());
self.set_targets(host, value);
}
if changed.contains(CompositionLightChangedFields::EXCLUSIONS_FROM_TARGETS) {
let value = read_server_object(reader, compositor.as_ref());
self.set_exclusions_from_targets(host, value);
}
if changed.contains(CompositionLightChangedFields::IS_ENABLED) {
let value = reader.read::<bool>();
self.set_is_enabled(host, value);
}
ServerCompositionLightHooks::on_fields_deserialized(host, changed);
}
pub fn get_composition_property(name: &str) -> Option<&'static CompositionProperty> {
if name == "IsEnabled" {
return Some(Self::id_of_is_enabled_property().base());
}
None
}
}