use super::*;
pub struct ValueAccessorReadWriteAnimate<T> {
id: Entity,
component: ComponentType,
param: u32,
_marker: std::marker::PhantomData<T>,
}
#[allow(missing_docs)]
#[derive(Copy, Clone)]
pub struct AnimationRequest {
pub id: Entity,
pub component: ComponentType,
pub param: u32,
pub target: Value,
pub options: AnimationOptions,
pub enqueue: bool,
}
pub struct AnimationBuilder<T> {
request: AnimationRequest,
_marker: std::marker::PhantomData<T>,
}
impl<T> AnimationBuilder<T>
where
ValueConverter: ValueConverterTrait<T>,
{
pub fn new(accessor: &ValueAccessorReadWriteAnimate<T>) -> Self {
Self {
_marker: std::marker::PhantomData,
request: AnimationRequest {
id: accessor.id,
component: accessor.component,
param: accessor.param,
options: AnimationOptions {
curve: AnimationCurve::Linear,
duration: 0.0,
loop_count: 1,
delay: 0.0,
smoothing: 0.0,
},
target: Value::none(),
enqueue: false,
},
}
}
pub fn delay(&mut self, seconds: f32) -> &mut Self {
self.request.options.delay = seconds;
self
}
pub fn target(&mut self, target: T, duration: f32) -> &mut Self {
self.request.target = <ValueConverter as ValueConverterTrait<T>>::into_value(target);
self.request.options.duration = duration;
self
}
pub fn curve(&mut self, curve: AnimationCurve) -> &mut Self {
self.request.options.curve = curve;
self
}
pub fn loop_count(&mut self, loop_count: u32) -> &mut Self {
self.request.options.loop_count = loop_count;
self
}
pub fn smoothing(&mut self, smoothing: f32) -> &mut Self {
self.request.options.smoothing = smoothing;
self
}
pub fn enqueue(&mut self) -> &mut Self {
self.request.enqueue = true;
self
}
pub fn submit(&self) {
Animation::enqueue_request_in_global_queue(&self.request);
}
pub fn submit_messenger(&self, callback: Option<Box<AnimationReplyFn<'static>>>) {
if let Some(callback) = callback {
EntityMessageDispatcher::global().animation_in_global_queue(&self.request, callback);
} else {
EntityMessenger::get()
.global_queue()
.animate_value_no_reply(&self.request);
}
}
#[allow(unused)]
#[inline]
fn build_request(&self) -> AnimationRequest {
self.request
}
}
impl<T> std::ops::Deref for AnimationBuilder<T>
where
ValueConverter: ValueConverterTrait<T>,
{
type Target = AnimationRequest;
#[inline]
fn deref(&self) -> &Self::Target {
&self.request
}
}
pub struct ValueAccessorRead<T> {
va: ValueAccessorReadWriteAnimate<T>,
}
impl<T> ValueAccessorRead<T>
where
ValueConverter: ValueConverterTrait<T>,
{
#[inline]
pub fn new(id: Entity, component: ComponentType, param: u32) -> Self {
Self {
va: ValueAccessorReadWriteAnimate::new(id, component, param),
}
}
#[inline]
pub fn get(&self) -> T {
self.va.get()
}
}
pub struct ValueAccessorReadWrite<T> {
va: ValueAccessorReadWriteAnimate<T>,
}
impl<T> ValueAccessorReadWrite<T>
where
ValueConverter: ValueConverterTrait<T>,
{
#[inline]
pub fn new(id: Entity, component: ComponentType, param: u32) -> Self {
Self {
va: ValueAccessorReadWriteAnimate::new(id, component, param),
}
}
#[inline]
pub fn set(&self, v: T) {
self.va.set(v);
}
#[inline]
pub fn get(&self) -> T {
self.va.get()
}
}
pub struct ValueAccessorDataReadWrite<T> {
va: ValueAccessorReadWriteAnimate<T>,
}
impl<T> ValueAccessorDataReadWrite<T>
where
ValueConverter: ValueConverterTrait<T>,
{
#[inline]
pub fn new(id: Entity, component: ComponentType, param: u32) -> Self {
Self {
va: ValueAccessorReadWriteAnimate::new(id, component, param),
}
}
#[inline]
fn get_handle(&self) -> DataHandle {
let v = World::get_entity_value(self.va.id, self.va.component, self.va.param);
<ValueConverter as ValueConverterTrait<DataHandle>>::from_value(&v)
}
fn set_handle(&self, handle: DataHandle) {
World::set_entity_value(
self.va.id,
self.va.component,
self.va.param,
&Value::from_i64(handle.as_ffi() as i64),
);
}
pub fn set(&self, v: T) {
let old_handle = self.get_handle();
self.va.set(v); let new_handle = self.get_handle();
if old_handle.is_valid() && (old_handle != new_handle) {
World::destroy_data(old_handle); }
}
pub fn reset(&self) {
let old_handle = self.get_handle();
if old_handle.is_valid() {
World::destroy_data(old_handle); }
self.set_handle(DataHandle::invalid());
}
#[inline]
pub fn get(&self) -> T {
self.va.get()
}
}
pub trait ValueAccessorWriteTrait<T>
where
ValueConverter: ValueConverterTrait<T>,
{
fn set(&self, v: T);
}
pub trait ValueAccessorReadTrait<T>
where
ValueConverter: ValueConverterTrait<T>,
{
fn get(&self) -> T;
}
pub trait ValueAccessorAnimateTrait<T>
where
ValueConverter: ValueConverterTrait<T>,
{
fn animate(&self, v: T, duration: f32);
fn animate_smooth(&self, v: T, duration: f32, smoothing: f32);
fn build_animation(&self) -> AnimationBuilder<T>;
}
impl<T> ValueAccessorReadWriteAnimate<T>
where
ValueConverter: ValueConverterTrait<T>,
{
#[inline]
pub fn new(id: Entity, component: ComponentType, param: u32) -> Self
where
T: Sized,
{
Self {
id,
component,
param,
_marker: std::marker::PhantomData,
}
}
#[inline]
pub fn set(&self, v: T) {
World::set_entity_value(
self.id,
self.component,
self.param,
&<ValueConverter as ValueConverterTrait<T>>::into_value(v),
);
}
#[inline]
pub fn get(&self) -> T {
let v = World::get_entity_value(self.id, self.component, self.param);
<ValueConverter as ValueConverterTrait<T>>::from_value(&v)
}
pub fn animate(&self, v: T, duration: f32) {
AnimationBuilder::<T>::new(self)
.target(v, duration)
.submit();
}
pub fn animate_smooth(&self, v: T, duration: f32, smoothing: f32) {
AnimationBuilder::<T>::new(self)
.target(v, duration)
.smoothing(smoothing)
.submit();
}
pub fn build_animation(&self) -> AnimationBuilder<T> {
AnimationBuilder::<T>::new(self)
}
}
impl<T> ValueAccessorReadTrait<T> for ValueAccessorRead<T>
where
ValueConverter: ValueConverterTrait<T>,
{
#[inline]
fn get(&self) -> T {
self.va.get()
}
}
impl<T> ValueAccessorReadTrait<T> for ValueAccessorReadWrite<T>
where
ValueConverter: ValueConverterTrait<T>,
{
#[inline]
fn get(&self) -> T {
self.get()
}
}
impl<T> ValueAccessorReadTrait<T> for ValueAccessorReadWriteAnimate<T>
where
ValueConverter: ValueConverterTrait<T>,
{
#[inline]
fn get(&self) -> T {
self.get()
}
}
impl<T> ValueAccessorWriteTrait<T> for ValueAccessorReadWrite<T>
where
ValueConverter: ValueConverterTrait<T>,
{
#[inline]
fn set(&self, v: T) {
self.set(v);
}
}
impl<T> ValueAccessorWriteTrait<T> for ValueAccessorReadWriteAnimate<T>
where
ValueConverter: ValueConverterTrait<T>,
{
#[inline]
fn set(&self, v: T) {
self.set(v);
}
}
impl<T> ValueAccessorAnimateTrait<T> for ValueAccessorReadWriteAnimate<T>
where
ValueConverter: ValueConverterTrait<T>,
{
fn animate(&self, v: T, duration: f32) {
self.animate(v, duration);
}
fn animate_smooth(&self, v: T, duration: f32, smoothing: f32) {
self.animate_smooth(v, duration, smoothing);
}
fn build_animation(&self) -> AnimationBuilder<T> {
self.build_animation()
}
}
#[macro_export]
macro_rules! impl_world_accessor {
($(#[$attr: meta])* $component_type: ident, $param_name: ident, $param_type: ty, $accessor_name: ident, $visibility: ident) => {
$(#[$attr])*
#[inline]
pub fn $accessor_name(&self) -> $visibility<$param_type> {
use ffi::$component_type;
$visibility::new(self.id, ffi::ComponentType::$component_type, $component_type::$param_name.into())
}
};
}
#[macro_export]
macro_rules! impl_world_accessor_indexed {
($(#[$attr: meta])* $component_type: ident, $param_name: ident, $param_type: ty, $accessor_name: ident, $index_type: ty, $visibility: ident) => {
$(#[$attr])*
#[inline]
pub fn $accessor_name(&self, index: $index_type) -> $visibility<$param_type> {
use ffi::$component_type;
let param_index: u32 = $component_type::$param_name.into();
$visibility::new(self.id, ffi::ComponentType::$component_type, param_index + index as u32)
}
};
}