From 5bf400fef3d907ffdf1b358d7c6e8a8b7d67317a Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 26 Feb 2024 05:36:46 -0800 Subject: [PATCH] Add dynamic `vec2` and `vec3` constructors to the expression grammar. (#285) There's currently no way to combine multiple dynamic scalar expressions into a scalar. This causes many problems, including not being able to convert an angle to a 2D vector, as demonstrated in the new doctests. This commit adds a new binary operator, `vec2`, and a new ternary operator, `vec3`, for this. Both operators work on all scalar types. --- src/graph/expr.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/graph/expr.rs b/src/graph/expr.rs index 9a2aa266..b1a8dec2 100644 --- a/src/graph/expr.rs +++ b/src/graph/expr.rs @@ -326,6 +326,7 @@ impl Module { impl_module_binary!(step, Step); impl_module_binary!(sub, Sub); impl_module_binary!(uniform, UniformRand); + impl_module_binary!(vec2, Vec2); /// Build a ternary expression and append it to the module. /// @@ -1545,6 +1546,12 @@ pub enum BinaryOperator { /// rank, and the result is a vector of that rank and same element /// scalar type. UniformRand, + + /// Constructor for 2-element vectors. + /// + /// Given two scalar elements `x` and `y`, returns the vector consisting of + /// those two elements `(x, y)`. + Vec2, } impl BinaryOperator { @@ -1571,7 +1578,8 @@ impl BinaryOperator { | BinaryOperator::Max | BinaryOperator::Min | BinaryOperator::Step - | BinaryOperator::UniformRand => true, + | BinaryOperator::UniformRand + | BinaryOperator::Vec2 => true, } } } @@ -1595,6 +1603,7 @@ impl ToWgslString for BinaryOperator { BinaryOperator::Step => "step".to_string(), BinaryOperator::Sub => "-".to_string(), BinaryOperator::UniformRand => "rand_uniform".to_string(), + BinaryOperator::Vec2 => "vec2".to_string(), } } } @@ -1630,6 +1639,12 @@ pub enum TernaryOperator { /// /// The result is always a floating point scalar in \[0:1\]. SmoothStep, + + /// Constructor for 3-element vectors. + /// + /// Given three scalar elements `x`, `y`, and `z`, returns the vector + /// consisting of those three elements `(x, y, z)`. + Vec3, } impl ToWgslString for TernaryOperator { @@ -1637,6 +1652,7 @@ impl ToWgslString for TernaryOperator { match *self { TernaryOperator::Mix => "mix".to_string(), TernaryOperator::SmoothStep => "smoothstep".to_string(), + TernaryOperator::Vec3 => "vec3".to_string(), } } } @@ -3008,6 +3024,38 @@ impl WriterExpr { low.ternary_op(high, self, TernaryOperator::SmoothStep) } + /// Construct a `Vec2` from two scalars. + /// + /// # Example + /// + /// ``` + /// # use bevy_hanabi::*; + /// # let mut w = ExprWriter::new(); + /// // Convert the angular property `theta` to a 2D vector. + /// let (cos_theta, sin_theta) = (w.prop("theta").cos(), w.prop("theta").sin()); + /// let circle_pos = cos_theta.vec2(sin_theta); + /// ``` + #[inline] + pub fn vec2(self, y: Self) -> Self { + self.binary_op(y, BinaryOperator::Vec2) + } + + /// Construct a `Vec3` from two scalars. + /// + /// # Example + /// + /// ``` + /// # use bevy_hanabi::*; + /// # let mut w = ExprWriter::new(); + /// // Convert the angular property `theta` to a 3D vector in a flat plane. + /// let (cos_theta, sin_theta) = (w.prop("theta").cos(), w.prop("theta").sin()); + /// let circle_pos = cos_theta.vec3(w.lit(0.0), sin_theta); + /// ``` + #[inline] + pub fn vec3(self, y: Self, z: Self) -> Self { + self.ternary_op(y, z, TernaryOperator::Vec3) + } + /// Cast an expression to a different type. /// /// # Example