From 87bcd0d167a117a4170c9849f8b65aff181a203f Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Sat, 15 Jun 2024 16:28:00 +0200 Subject: [PATCH] Implement some UI interpolators (#33) * Split interpolators into own files * Add UI interpolators --- CHANGELOG.md | 27 ++- Cargo.lock | 87 ++++++++ Cargo.toml | 69 +++---- src/interpolate.rs | 339 ++++---------------------------- src/interpolate/blanket_impl.rs | 43 ++++ src/interpolate/sprite.rs | 74 +++++++ src/interpolate/transform.rs | 174 ++++++++++++++++ src/interpolate/ui.rs | 69 +++++++ src/utils.rs | 2 +- 9 files changed, 544 insertions(+), 340 deletions(-) create mode 100644 src/interpolate/blanket_impl.rs create mode 100644 src/interpolate/sprite.rs create mode 100644 src/interpolate/transform.rs create mode 100644 src/interpolate/ui.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index d26be9f..1b74913 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,16 @@ # Changelog +## Unreleased + +### Changes + +- Add interpolators for some UI components when using the `bevy_ui` feature. + - `BackgroundColor` and `BorderColor` + ## v0.5.0 - 2024-06-09 ### Breaking changes + - Move span_tweener and tween_timer types to `bevy_time_runner` - Remove `tween_timer` module and all types in it. Some types can be found in `bevy_time_runner` - Remove `span_tween` module and all types in it @@ -13,7 +21,8 @@ - Update library to use types from `bevy_time_runner` - Remove all types, method, and function related to tweener. Most is renamed and move to `bevy_time_runner` -All timing types is moved to `bevy_time_runner` including some changes. +All timing types is moved to `bevy_time_runner` including some changes. + - `Repeat` - `RepeatStyle` - `SpanTweener` is replaced with `TimeRunner` @@ -23,9 +32,11 @@ All timing types is moved to `bevy_time_runner` including some changes. - ...And some more ### Fixes + - Fix tween systems error will flood the console ### Changes + - Supports `bevy_eventlistener` #16 by musjj - Interpolation implementation for bevy_lookup_curve - Update readme @@ -41,7 +52,7 @@ All timing types is moved to `bevy_time_runner` including some changes. - pub use bevy_time_runner - `TweenCorePlugin` adds `TimeRunnerPlugin` automatically if not exists - Remove deprecated systems and types -- Add build.rs file to actually make CHANNEL_NIGHTLY cfg flag works +- Add build.rs file to actually make CHANNEL_NIGHTLY cfg flag works - Update all examples to account for new changes - Add rustc_version to build dependencies - Remove span_tween example @@ -50,6 +61,7 @@ All timing types is moved to `bevy_time_runner` including some changes. ## v0.4.0 - 2024-04-08 ### Changes + - Add `SpanTweensBuilder::add` trait - Add `SpanTweenPreset` trait - Update examples to use the preset APIs. @@ -59,11 +71,13 @@ All timing types is moved to `bevy_time_runner` including some changes. - Add "Your contributions" section to README.md ## v0.3.1 - 2024-04-04 + - Fix README.md ## v0.3.0 - 2024-04-03 ### Breaking Changes + - Remove unnecessary generics from `TargetComponent` and `TargetResource` - Add `app_resource: TweenAppResource` field to `TweenCorePlugin` - All plugins and APIs that uses `PostUpdate` schedule is changed to use schedule from @@ -71,7 +85,7 @@ All timing types is moved to `bevy_time_runner` including some changes. - Delegate `span_tweener_system()`'s ticking responsibility to `tick_span_tweener_system()` - Remove `Eq` and `Hash` derives from `SpanTweener`, `Elasped`, and `TweenTimer` - Remove `new()` from `Elasped` -- Remove `state: TweenState` field from SpanTweenBundle +- Remove `state: TweenState` field from SpanTweenBundle - Remove `TweenState` - Remove `TweenTarget` impl from `TargetComponent`, `TargetResource` and, `TargetAsset` - Change `component_tween_system_full`, `resource_tween_system_full`, and `asset_tween_system_full` @@ -86,6 +100,7 @@ All timing types is moved to `bevy_time_runner` including some changes. - Change `Repeat` to use `i32` instead of `usize` and update their corresponding methods. ### Changes + - Add `TweenAppResource` - Add `DefaultTweenEventsPlugin` - Add `TweenEventData` @@ -116,11 +131,13 @@ All timing types is moved to `bevy_time_runner` including some changes. - Improves `span_tweener_system` code to account to new `TweenTimer::tick()` behavior ### Fixes + - Fixed missing `AngleZ` tween system in `DefaultInterpolatorsPlugin` ### Deprecates -- Deprecate `QuickSpanTweenBundle` -- Deprecate `span_tween::span_tween()` + +- Deprecate `QuickSpanTweenBundle` +- Deprecate `span_tween::span_tween()` - Deprecate `ChildSpanTweenBuilder` - Deprecate `ChildSpanTweenBuilderExt` - Deprecate `WorldChildSpanTweenBuilder` diff --git a/Cargo.lock b/Cargo.lock index dbec740..fcda073 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -629,8 +629,10 @@ dependencies = [ "bevy_scene", "bevy_sprite", "bevy_tasks", + "bevy_text", "bevy_time", "bevy_transform", + "bevy_ui", "bevy_utils", "bevy_window", ] @@ -882,6 +884,28 @@ dependencies = [ "wasm-bindgen-futures", ] +[[package]] +name = "bevy_text" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4e8456ae0bea7d6b7621e42c1c12bf66c0891381e62c948ab23920673ce611c" +dependencies = [ + "ab_glyph", + "bevy_app", + "bevy_asset", + "bevy_ecs", + "bevy_math", + "bevy_reflect", + "bevy_render", + "bevy_sprite", + "bevy_transform", + "bevy_utils", + "bevy_window", + "glyph_brush_layout", + "serde", + "thiserror", +] + [[package]] name = "bevy_time" version = "0.13.2" @@ -939,6 +963,34 @@ dependencies = [ "serde", ] +[[package]] +name = "bevy_ui" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bbc30be39cfbfa3a073b541d22aea43ab14452dea12d7411ce201df17ff7b1" +dependencies = [ + "bevy_a11y", + "bevy_app", + "bevy_asset", + "bevy_core_pipeline", + "bevy_derive", + "bevy_ecs", + "bevy_hierarchy", + "bevy_input", + "bevy_log", + "bevy_math", + "bevy_reflect", + "bevy_render", + "bevy_sprite", + "bevy_text", + "bevy_transform", + "bevy_utils", + "bevy_window", + "bytemuck", + "taffy", + "thiserror", +] + [[package]] name = "bevy_utils" version = "0.13.2" @@ -1761,6 +1813,17 @@ dependencies = [ "gl_generator", ] +[[package]] +name = "glyph_brush_layout" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc32c2334f00ca5ac3695c5009ae35da21da8c62d255b5b96d56e2597a637a38" +dependencies = [ + "ab_glyph", + "approx", + "xi-unicode", +] + [[package]] name = "gpu-alloc" version = "0.6.0" @@ -1813,6 +1876,12 @@ dependencies = [ "bitflags 2.5.0", ] +[[package]] +name = "grid" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eec1c01eb1de97451ee0d60de7d81cf1e72aabefb021616027f3d1c3ec1c723c" + [[package]] name = "guillotiere" version = "0.6.2" @@ -2900,6 +2969,18 @@ dependencies = [ "windows 0.52.0", ] +[[package]] +name = "taffy" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1315457ccd9c3def787a18fae91914e623e4dcff019b64ce39f5268ded53d3d" +dependencies = [ + "arrayvec", + "grid", + "num-traits", + "slotmap", +] + [[package]] name = "termcolor" version = "1.4.1" @@ -3747,6 +3828,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" +[[package]] +name = "xi-unicode" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" + [[package]] name = "xkbcommon-dl" version = "0.4.2" diff --git a/Cargo.toml b/Cargo.toml index e88a226..2f79a04 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,14 +3,14 @@ name = "bevy_tween" description = "Flexible tweening plugin library for Bevy" version = "0.5.0" edition = "2021" -authors = [ "Multirious" ] -license = "MIT OR Apache-2.0" +authors = ["Multirious"] +license = "MIT OR Apache-2.0" repository = "https://github.com/Multirious/bevy_tween" homepage = "https://github.com/Multirious/bevy_tween" documentation = "https://docs.rs/bevy_tween" readme = "README.md" -keywords = [ "bevy", "tween", "tweening", "easing", "animation" ] -categories = [ "game-development" ] +keywords = ["bevy", "tween", "tweening", "easing", "animation"] +categories = ["game-development"] [workspace] resolver = "2" @@ -27,7 +27,7 @@ serde = { version = "1", optional = true, features = ["derive"] } [dev-dependencies] bevy-inspector-egui = "0.23" bevy_eventlistener = { version = "0.7.0" } -bevy = { version = "0.13.0", default-features = false, features = [ "bevy_asset", "bevy_render", "bevy_sprite", "tonemapping_luts", "png" ] } +bevy = { version = "0.13.0", default-features = false, features = ["bevy_asset", "bevy_render", "bevy_sprite", "tonemapping_luts", "png"] } rand = "0.8.5" [build-dependencies] @@ -35,24 +35,27 @@ rustc_version = "0.4.0" [features] default = [ - "bevy_asset", - "bevy_render", - "bevy_sprite", - "bevy_eventlistener" + "bevy_asset", + "bevy_render", + "bevy_sprite", + "bevy_eventlistener", + "bevy_ui", ] # Adds tweening systems for asset -bevy_asset = [ "bevy/bevy_asset" ] +bevy_asset = ["bevy/bevy_asset"] # Adds nothing just yet but required by the "bevy_sprite" feature. -bevy_render = [ "bevy/bevy_render"] -# Add some built-in interpolator related to sprite -bevy_sprite = [ "bevy/bevy_sprite", "bevy_render" ] +bevy_render = ["bevy/bevy_render"] +# Add some built-in interpolators related to sprite +bevy_sprite = ["bevy/bevy_sprite", "bevy_render"] +# Adds some built-in interpolators related to ui +bevy_ui = ["bevy/bevy_ui"] # Add entity-targeted events with bevy_eventlistener -bevy_eventlistener = [ "dep:bevy_eventlistener", "bevy_time_runner/bevy_eventlistener" ] +bevy_eventlistener = ["dep:bevy_eventlistener", "bevy_time_runner/bevy_eventlistener"] # Supports for `bevy_lookup_curve` (https://github.com/villor/bevy_lookup_curve) -bevy_lookup_curve = [ "dep:bevy_lookup_curve" ] +bevy_lookup_curve = ["dep:bevy_lookup_curve"] # Derive Serialize and Deserialize for some types -serde = [ "dep:serde" ] +serde = ["dep:serde"] [package.metadata.docs.rs] all-features = true @@ -61,69 +64,69 @@ all-features = true name = "banner_bounce" path = "examples/animation/banner_bounce.rs" required-features = [ - "bevy_sprite", - "bevy_asset", + "bevy_sprite", + "bevy_asset", ] [[example]] name = "banner_triangle" path = "examples/animation/banner_triangle.rs" required-features = [ - "bevy_sprite", - "bevy_asset", + "bevy_sprite", + "bevy_asset", ] [[example]] name = "thumbnail_triangle" path = "examples/animation/thumbnail_triangle.rs" required-features = [ - "bevy_sprite", + "bevy_sprite", ] [[example]] name = "follow" path = "examples/demo/follow.rs" required-features = [ - "bevy_sprite", - "bevy_asset", + "bevy_sprite", + "bevy_asset", ] [[example]] name = "click" path = "examples/demo/click.rs" required-features = [ - "bevy_sprite", - "bevy_asset", + "bevy_sprite", + "bevy_asset", ] [[example]] name = "hold" path = "examples/demo/hold.rs" required-features = [ - "bevy_sprite", - "bevy_asset", + "bevy_sprite", + "bevy_asset", ] [[example]] name = "event" path = "examples/demo/event.rs" required-features = [ - "bevy_sprite", - "bevy_asset", + "bevy_sprite", + "bevy_asset", ] [[example]] name = "entity_event" path = "examples/demo/entity_event.rs" required-features = [ - "bevy_eventlistener" + "bevy_eventlistener" ] [[example]] name = "sprite_sheet" path = "examples/demo/sprite_sheet.rs" required-features = [ - "bevy_sprite", + "bevy_sprite", ] [[example]] @@ -134,6 +137,6 @@ path = "examples/entity_structure.rs" name = "bevy_lookup_curve" path = "examples/bevy_lookup_curve.rs" required-features = [ - "bevy_sprite", - "bevy_lookup_curve", + "bevy_sprite", + "bevy_lookup_curve", ] diff --git a/src/interpolate.rs b/src/interpolate.rs index 04e7dc9..1d45a97 100644 --- a/src/interpolate.rs +++ b/src/interpolate.rs @@ -69,13 +69,23 @@ //! [`resource_tween_system`]: crate::tween::resource_tween_system //! [`asset_tween_system`]: crate::tween::asset_tween_system -use std::sync::Arc; +mod blanket_impl; +#[cfg(feature = "bevy_sprite")] +mod sprite; +mod transform; +#[cfg(feature = "bevy_ui")] +mod ui; -use bevy::prelude::*; +pub use transform::*; #[cfg(feature = "bevy_sprite")] -use crate::utils::color_lerp; +pub use sprite::*; + +#[cfg(feature = "bevy_ui")] +pub use ui::*; + use crate::{tween, BevyTweenRegisterSystems}; +use bevy::prelude::*; /// Alias for an `Interpolator` as a boxed trait object. pub type BoxedInterpolator = Box>; @@ -185,47 +195,6 @@ pub trait Interpolator: Send + Sync + 'static { // } // } -impl Interpolator for Box -where - I: Interpolator + ?Sized, -{ - type Item = I::Item; - - fn interpolate(&self, item: &mut Self::Item, value: f32) { - (**self).interpolate(item, value) - } -} - -impl Interpolator for &'static I -where - I: Interpolator + ?Sized, -{ - type Item = I::Item; - - fn interpolate(&self, item: &mut Self::Item, value: f32) { - (**self).interpolate(item, value) - } -} - -impl Interpolator for Arc -where - I: Interpolator + ?Sized, -{ - type Item = I::Item; - - fn interpolate(&self, item: &mut Self::Item, value: f32) { - (**self).interpolate(item, value) - } -} - -impl Interpolator for dyn Fn(&mut I, f32) + Send + Sync + 'static { - type Item = I; - - fn interpolate(&self, item: &mut Self::Item, value: f32) { - self(item, value) - } -} - /// Default interpolators /// /// Register type and systems for the following interpolators: @@ -233,8 +202,8 @@ impl Interpolator for dyn Fn(&mut I, f32) + Send + Sync + 'static { /// - [`Rotation`] /// - [`Scale`] /// - [`AngleZ`] -/// - [`SpriteColor`] if `"bevy_sprite"` feature is enabled. -/// - [`ColorMaterial`] if `"bevy_sprite"` feature is enabled. +/// - [`SpriteColor`] and [`ColorMaterial`] if `"bevy_sprite"` feature is enabled. +/// - [`BackgroundColor`] and [`BorderColor`] if `"bevy_ui"` feature is enabled. pub struct DefaultInterpolatorsPlugin; impl Plugin for DefaultInterpolatorsPlugin { /// # Panics @@ -258,9 +227,19 @@ impl Plugin for DefaultInterpolatorsPlugin { app.add_tween_systems(tween::component_tween_system::()) .register_type::>(); + #[cfg(feature = "bevy_ui")] + app.add_tween_systems(( + tween::component_tween_system::(), + tween::component_tween_system::(), + )) + .register_type::>() + .register_type::>(); + #[cfg(all(feature = "bevy_sprite", feature = "bevy_asset",))] - app.add_tween_systems(tween::asset_tween_system::()) - .register_type::>(); + app.add_tween_systems( + tween::asset_tween_system::(), + ) + .register_type::>(); } } @@ -270,6 +249,7 @@ impl Plugin for DefaultInterpolatorsPlugin { /// - [`Transform`] component. /// - [`Sprite`] component if `"bevy_sprite"` feature is enabled. /// - [`ColorMaterial`] asset if `"bevy_sprite"` feature is enabled. +/// - [`BackgroundColor`] and [`BorderColor`] components if `"bevy_ui"` feature is enabled. /// /// [`ColorMaterial`]: bevy::sprite::ColorMaterial pub struct DefaultDynInterpolatorsPlugin; @@ -289,262 +269,19 @@ impl Plugin for DefaultDynInterpolatorsPlugin { BoxedInterpolator, >()); + #[cfg(feature = "bevy_ui")] + app.add_tween_systems(( + tween::component_tween_system::< + BoxedInterpolator, + >(), + tween::component_tween_system::< + BoxedInterpolator, + >(), + )); + #[cfg(all(feature = "bevy_sprite", feature = "bevy_asset",))] app.add_tween_systems(tween::asset_tween_system::< BoxedInterpolator, >()); } } - -// type ReflectInterpolatorTransform = ReflectInterpolator; - -/// [`Interpolator`] for [`Transform`]'s translation. -#[derive(Debug, Default, Clone, PartialEq, Reflect)] -// #[reflect(InterpolatorTransform)] -pub struct Translation { - #[allow(missing_docs)] - pub start: Vec3, - #[allow(missing_docs)] - pub end: Vec3, -} -impl Interpolator for Translation { - type Item = Transform; - - fn interpolate(&self, item: &mut Self::Item, value: f32) { - item.translation = self.start.lerp(self.end, value); - } -} - -/// Constructor for [`Translation`] -pub fn translation(start: Vec3, end: Vec3) -> Translation { - Translation { start, end } -} - -/// Constructor for [`Translation`] that's relative to previous value using currying. -pub fn translation_to(to: Vec3) -> impl Fn(&mut Vec3) -> Translation { - move |state| { - let start = *state; - let end = to; - *state = to; - translation(start, end) - } -} - -/// Constructor for [`Translation`] that's relative to previous value using currying. -pub fn translation_by(by: Vec3) -> impl Fn(&mut Vec3) -> Translation { - move |state| { - let start = *state; - let end = *state + by; - *state += by; - translation(start, end) - } -} - -/// [`Interpolator`] for [`Transform`]'s rotation using the [`Quat::slerp`] function. -#[derive(Debug, Default, Clone, PartialEq, Reflect)] -// #[reflect(InterpolatorTransform)] -pub struct Rotation { - #[allow(missing_docs)] - pub start: Quat, - #[allow(missing_docs)] - pub end: Quat, -} -impl Interpolator for Rotation { - type Item = Transform; - - fn interpolate(&self, item: &mut Self::Item, value: f32) { - item.rotation = self.start.slerp(self.end, value); - } -} - -/// Constructor for [`Rotation`] -pub fn rotation(start: Quat, end: Quat) -> Rotation { - Rotation { start, end } -} - -/// Constructor for [`Rotation`] that's relative to previous value using currying. -pub fn rotation_to(to: Quat) -> impl Fn(&mut Quat) -> Rotation { - move |state| { - let start = *state; - let end = to; - *state = to; - rotation(start, end) - } -} - -/// Constructor for [`Rotation`] that's relative to previous value using currying. -pub fn rotation_by(by: Quat) -> impl Fn(&mut Quat) -> Rotation { - move |state| { - let start = *state; - let end = *state + by; - *state = state.mul_quat(by); - rotation(start, end) - } -} - -/// [`Interpolator`] for [`Transform`]'s scale -#[derive(Debug, Default, Clone, PartialEq, Reflect)] -// #[reflect(InterpolatorTransform)] -pub struct Scale { - #[allow(missing_docs)] - pub start: Vec3, - #[allow(missing_docs)] - pub end: Vec3, -} -impl Interpolator for Scale { - type Item = Transform; - - fn interpolate(&self, item: &mut Self::Item, value: f32) { - item.scale = self.start.lerp(self.end, value); - } -} - -/// Constructor for [`Scale`] -pub fn scale(start: Vec3, end: Vec3) -> Scale { - Scale { start, end } -} - -/// Constructor for [`Scale`] that's relative to previous value using currying. -pub fn scale_to(to: Vec3) -> impl Fn(&mut Vec3) -> Scale { - move |state| { - let start = *state; - let end = to; - *state = to; - scale(start, end) - } -} - -/// Constructor for [`Scale`] that's relative to previous value using currying. -pub fn scale_by(by: Vec3) -> impl Fn(&mut Vec3) -> Scale { - move |state| { - let start = *state; - let end = *state + by; - *state += by; - scale(start, end) - } -} - -/// [`Interpolator`] for [`Transform`]'s rotation at Z axis. -/// Usually used for 2D rotation. -#[derive(Debug, Default, Clone, PartialEq, Reflect)] -// #[reflect(InterpolatorTransform)] -pub struct AngleZ { - #[allow(missing_docs)] - pub start: f32, - #[allow(missing_docs)] - pub end: f32, -} -impl Interpolator for AngleZ { - type Item = Transform; - - fn interpolate(&self, item: &mut Self::Item, value: f32) { - let angle = (self.end - self.start).mul_add(value, self.start); - item.rotation = Quat::from_rotation_z(angle); - } -} - -/// Constructor for [`AngleZ`] -pub fn angle_z(start: f32, end: f32) -> AngleZ { - AngleZ { start, end } -} - -/// Constructor for [`AngleZ`] that's relative to previous value using currying. -pub fn angle_z_to(to: f32) -> impl Fn(&mut f32) -> AngleZ { - move |state| { - let start = *state; - let end = to; - *state = to; - angle_z(start, end) - } -} - -/// Constructor for [`AngleZ`] that's relative to previous value using currying. -pub fn angle_z_by(by: f32) -> impl Fn(&mut f32) -> AngleZ { - move |state| { - let start = *state; - let end = *state + by; - *state += by; - angle_z(start, end) - } -} - -// #[cfg(feature = "bevy_sprite")] -// type ReflectInterpolatorSprite = ReflectInterpolator; - -/// [`Interpolator`] for [`Sprite`]'s color -#[cfg(feature = "bevy_sprite")] -#[derive(Debug, Default, Clone, PartialEq, Reflect)] -// #[reflect(InterpolatorSprite)] -pub struct SpriteColor { - #[allow(missing_docs)] - pub start: Color, - #[allow(missing_docs)] - pub end: Color, -} - -#[cfg(feature = "bevy_sprite")] -impl Interpolator for SpriteColor { - type Item = Sprite; - - fn interpolate(&self, item: &mut Self::Item, value: f32) { - item.color = color_lerp(self.start, self.end, value) - } -} - -/// Constructor for [`SpriteColor`] -#[cfg(feature = "bevy_sprite")] -pub fn sprite_color(start: Color, end: Color) -> SpriteColor { - SpriteColor { start, end } -} - -/// Constructor for [`SpriteColor`] that's relative to previous value using currying. -#[cfg(feature = "bevy_sprite")] -pub fn sprite_color_to(to: Color) -> impl Fn(&mut Color) -> SpriteColor { - move |state| { - let start = *state; - let end = to; - *state = to; - sprite_color(start, end) - } -} - -// #[cfg(feature = "bevy_sprite")] -// type ReflectInterpolatorColorMaterial = -// ReflectInterpolator; - -/// [`Interpolator`] for [`Sprite`]'s [`ColorMaterial`] -#[cfg(feature = "bevy_sprite")] -#[derive(Debug, Default, Clone, PartialEq, Reflect)] -// #[reflect(InterpolatorColorMaterial)] -pub struct ColorMaterial { - #[allow(missing_docs)] - pub start: Color, - #[allow(missing_docs)] - pub end: Color, -} - -#[cfg(feature = "bevy_sprite")] -impl Interpolator for ColorMaterial { - type Item = bevy::sprite::ColorMaterial; - - fn interpolate(&self, item: &mut Self::Item, value: f32) { - item.color = color_lerp(self.start, self.end, value); - } -} - -/// Constructor for [`ColorMaterial`] -#[cfg(feature = "bevy_sprite")] -pub fn color_material(start: Color, end: Color) -> ColorMaterial { - ColorMaterial { start, end } -} - -/// Constructor for [`ColorMaterial`] that's relative to previous value using currying. -#[cfg(feature = "bevy_sprite")] -pub fn color_material_to(to: Color) -> impl Fn(&mut Color) -> ColorMaterial { - move |state| { - let start = *state; - let end = to; - *state = to; - color_material(start, end) - } -} diff --git a/src/interpolate/blanket_impl.rs b/src/interpolate/blanket_impl.rs new file mode 100644 index 0000000..8226160 --- /dev/null +++ b/src/interpolate/blanket_impl.rs @@ -0,0 +1,43 @@ +use crate::interpolate::Interpolator; +use std::sync::Arc; + +impl Interpolator for Box +where + I: Interpolator + ?Sized, +{ + type Item = I::Item; + + fn interpolate(&self, item: &mut Self::Item, value: f32) { + (**self).interpolate(item, value) + } +} + +impl Interpolator for &'static I +where + I: Interpolator + ?Sized, +{ + type Item = I::Item; + + fn interpolate(&self, item: &mut Self::Item, value: f32) { + (**self).interpolate(item, value) + } +} + +impl Interpolator for Arc +where + I: Interpolator + ?Sized, +{ + type Item = I::Item; + + fn interpolate(&self, item: &mut Self::Item, value: f32) { + (**self).interpolate(item, value) + } +} + +impl Interpolator for dyn Fn(&mut I, f32) + Send + Sync + 'static { + type Item = I; + + fn interpolate(&self, item: &mut Self::Item, value: f32) { + self(item, value) + } +} diff --git a/src/interpolate/sprite.rs b/src/interpolate/sprite.rs new file mode 100644 index 0000000..4e179f8 --- /dev/null +++ b/src/interpolate/sprite.rs @@ -0,0 +1,74 @@ +use crate::interpolate::Interpolator; +use crate::utils::color_lerp; +use bevy::prelude::*; + +// type ReflectInterpolatorSprite = ReflectInterpolator; + +/// [`Interpolator`] for [`Sprite`]'s color +#[derive(Debug, Default, Clone, PartialEq, Reflect)] +// #[reflect(InterpolatorSprite)] +pub struct SpriteColor { + #[allow(missing_docs)] + pub start: Color, + #[allow(missing_docs)] + pub end: Color, +} + +impl Interpolator for SpriteColor { + type Item = Sprite; + + fn interpolate(&self, item: &mut Self::Item, value: f32) { + item.color = color_lerp(self.start, self.end, value) + } +} + +/// Constructor for [`SpriteColor`] +pub fn sprite_color(start: Color, end: Color) -> SpriteColor { + SpriteColor { start, end } +} + +/// Constructor for [`SpriteColor`] that's relative to previous value using currying. +pub fn sprite_color_to(to: Color) -> impl Fn(&mut Color) -> SpriteColor { + move |state| { + let start = *state; + let end = to; + *state = to; + sprite_color(start, end) + } +} + +// type ReflectInterpolatorColorMaterial = +// ReflectInterpolator; + +/// [`Interpolator`] for [`Sprite`]'s [`ColorMaterial`] +#[derive(Debug, Default, Clone, PartialEq, Reflect)] +// #[reflect(InterpolatorColorMaterial)] +pub struct ColorMaterial { + #[allow(missing_docs)] + pub start: Color, + #[allow(missing_docs)] + pub end: Color, +} + +impl Interpolator for ColorMaterial { + type Item = bevy::sprite::ColorMaterial; + + fn interpolate(&self, item: &mut Self::Item, value: f32) { + item.color = color_lerp(self.start, self.end, value); + } +} + +/// Constructor for [`ColorMaterial`](crate::interpolate::ColorMaterial) +pub fn color_material(start: Color, end: Color) -> ColorMaterial { + ColorMaterial { start, end } +} + +/// Constructor for [`ColorMaterial`](crate::interpolate::ColorMaterial) that's relative to previous value using currying. +pub fn color_material_to(to: Color) -> impl Fn(&mut Color) -> ColorMaterial { + move |state| { + let start = *state; + let end = to; + *state = to; + color_material(start, end) + } +} diff --git a/src/interpolate/transform.rs b/src/interpolate/transform.rs new file mode 100644 index 0000000..e3f41b3 --- /dev/null +++ b/src/interpolate/transform.rs @@ -0,0 +1,174 @@ +// type ReflectInterpolatorTransform = ReflectInterpolator; + +use crate::interpolate::Interpolator; +use bevy::prelude::*; + +/// [`Interpolator`] for [`Transform`]'s translation. +#[derive(Debug, Default, Clone, PartialEq, Reflect)] +// #[reflect(InterpolatorTransform)] +pub struct Translation { + #[allow(missing_docs)] + pub start: Vec3, + #[allow(missing_docs)] + pub end: Vec3, +} +impl Interpolator for Translation { + type Item = Transform; + + fn interpolate(&self, item: &mut Self::Item, value: f32) { + item.translation = self.start.lerp(self.end, value); + } +} + +/// Constructor for [`Translation`] +pub fn translation(start: Vec3, end: Vec3) -> Translation { + Translation { start, end } +} + +/// Constructor for [`Translation`] that's relative to previous value using currying. +pub fn translation_to(to: Vec3) -> impl Fn(&mut Vec3) -> Translation { + move |state| { + let start = *state; + let end = to; + *state = to; + translation(start, end) + } +} + +/// Constructor for [`Translation`] that's relative to previous value using currying. +pub fn translation_by(by: Vec3) -> impl Fn(&mut Vec3) -> Translation { + move |state| { + let start = *state; + let end = *state + by; + *state += by; + translation(start, end) + } +} + +/// [`Interpolator`] for [`Transform`]'s rotation using the [`Quat::slerp`] function. +#[derive(Debug, Default, Clone, PartialEq, Reflect)] +// #[reflect(InterpolatorTransform)] +pub struct Rotation { + #[allow(missing_docs)] + pub start: Quat, + #[allow(missing_docs)] + pub end: Quat, +} +impl Interpolator for Rotation { + type Item = Transform; + + fn interpolate(&self, item: &mut Self::Item, value: f32) { + item.rotation = self.start.slerp(self.end, value); + } +} + +/// Constructor for [`Rotation`] +pub fn rotation(start: Quat, end: Quat) -> Rotation { + Rotation { start, end } +} + +/// Constructor for [`Rotation`] that's relative to previous value using currying. +pub fn rotation_to(to: Quat) -> impl Fn(&mut Quat) -> Rotation { + move |state| { + let start = *state; + let end = to; + *state = to; + rotation(start, end) + } +} + +/// Constructor for [`Rotation`] that's relative to previous value using currying. +pub fn rotation_by(by: Quat) -> impl Fn(&mut Quat) -> Rotation { + move |state| { + let start = *state; + let end = *state + by; + *state = state.mul_quat(by); + rotation(start, end) + } +} + +/// [`Interpolator`] for [`Transform`]'s scale +#[derive(Debug, Default, Clone, PartialEq, Reflect)] +// #[reflect(InterpolatorTransform)] +pub struct Scale { + #[allow(missing_docs)] + pub start: Vec3, + #[allow(missing_docs)] + pub end: Vec3, +} +impl Interpolator for Scale { + type Item = Transform; + + fn interpolate(&self, item: &mut Self::Item, value: f32) { + item.scale = self.start.lerp(self.end, value); + } +} + +/// Constructor for [`Scale`] +pub fn scale(start: Vec3, end: Vec3) -> Scale { + Scale { start, end } +} + +/// Constructor for [`Scale`] that's relative to previous value using currying. +pub fn scale_to(to: Vec3) -> impl Fn(&mut Vec3) -> Scale { + move |state| { + let start = *state; + let end = to; + *state = to; + scale(start, end) + } +} + +/// Constructor for [`Scale`] that's relative to previous value using currying. +pub fn scale_by(by: Vec3) -> impl Fn(&mut Vec3) -> Scale { + move |state| { + let start = *state; + let end = *state + by; + *state += by; + scale(start, end) + } +} + +/// [`Interpolator`] for [`Transform`]'s rotation at Z axis. +/// Usually used for 2D rotation. +#[derive(Debug, Default, Clone, PartialEq, Reflect)] +// #[reflect(InterpolatorTransform)] +pub struct AngleZ { + #[allow(missing_docs)] + pub start: f32, + #[allow(missing_docs)] + pub end: f32, +} +impl Interpolator for AngleZ { + type Item = Transform; + + fn interpolate(&self, item: &mut Self::Item, value: f32) { + let angle = (self.end - self.start).mul_add(value, self.start); + item.rotation = Quat::from_rotation_z(angle); + } +} + +/// Constructor for [`AngleZ`] +pub fn angle_z(start: f32, end: f32) -> AngleZ { + AngleZ { start, end } +} + +/// Constructor for [`AngleZ`] that's relative to previous value using currying. +pub fn angle_z_to(to: f32) -> impl Fn(&mut f32) -> AngleZ { + move |state| { + let start = *state; + let end = to; + *state = to; + angle_z(start, end) + } +} + +/// Constructor for [`AngleZ`] that's relative to previous value using currying. +pub fn angle_z_by(by: f32) -> impl Fn(&mut f32) -> AngleZ { + move |state| { + let start = *state; + let end = *state + by; + *state += by; + angle_z(start, end) + } +} diff --git a/src/interpolate/ui.rs b/src/interpolate/ui.rs new file mode 100644 index 0000000..31e67e1 --- /dev/null +++ b/src/interpolate/ui.rs @@ -0,0 +1,69 @@ +use crate::prelude::Interpolator; +use crate::utils::color_lerp; +use bevy::prelude::*; + +/// [`Interpolator`] for Bevy's [`BackgroundColor`](bevy::prelude::BackgroundColor) used in UIs. +#[derive(Debug, Default, Clone, PartialEq, Reflect)] +pub struct BackgroundColor { + #[allow(missing_docs)] + pub start: Color, + #[allow(missing_docs)] + pub end: Color, +} + +impl Interpolator for BackgroundColor { + type Item = bevy::prelude::BackgroundColor; + + fn interpolate(&self, item: &mut Self::Item, value: f32) { + item.0 = color_lerp(self.start, self.end, value) + } +} + +/// Constructor for [`BackgroundColor`](crate::interpolate::BackgroundColor) +pub fn background_color(start: Color, end: Color) -> BackgroundColor { + BackgroundColor { start, end } +} + +/// Constructor for [`BackgroundColor`](crate::interpolate::BackgroundColor) that's relative to previous value using currying. +pub fn background_color_to( + to: Color, +) -> impl Fn(&mut Color) -> BackgroundColor { + move |state| { + let start = *state; + let end = to; + *state = to; + background_color(start, end) + } +} + +/// [`Interpolator`] for Bevy's [`BorderColor`](bevy::prelude::BorderColor) used in UIs. +#[derive(Debug, Default, Clone, PartialEq, Reflect)] +pub struct BorderColor { + #[allow(missing_docs)] + pub start: Color, + #[allow(missing_docs)] + pub end: Color, +} + +impl Interpolator for BorderColor { + type Item = bevy::prelude::BorderColor; + + fn interpolate(&self, item: &mut Self::Item, value: f32) { + item.0 = color_lerp(self.start, self.end, value) + } +} + +/// Constructor for [`BorderColor`](crate::interpolate::BorderColor) +pub fn border_color(start: Color, end: Color) -> BorderColor { + BorderColor { start, end } +} + +/// Constructor for [`BorderColor`](crate::interpolate::BorderColor) that's relative to previous value using currying. +pub fn border_color_to(to: Color) -> impl Fn(&mut Color) -> BorderColor { + move |state| { + let start = *state; + let end = to; + *state = to; + border_color(start, end) + } +} diff --git a/src/utils.rs b/src/utils.rs index 5bb1089..9ffbc48 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -2,7 +2,7 @@ #![allow(unused)] use bevy::prelude::*; -#[cfg(feature = "bevy_render")] +#[cfg(any(feature = "bevy_render", feature = "bevy_ui"))] pub fn color_lerp(start: Color, end: Color, v: f32) -> Color { let Color::Rgba { red: start_red,