Skip to content

Commit

Permalink
Add dynamic vec2 and vec3 constructors to the expression grammar. (
Browse files Browse the repository at this point in the history
…#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.
  • Loading branch information
pcwalton authored Feb 26, 2024
1 parent fe3680b commit 5bf400f
Showing 1 changed file with 49 additions and 1 deletion.
50 changes: 49 additions & 1 deletion src/graph/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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 {
Expand All @@ -1571,7 +1578,8 @@ impl BinaryOperator {
| BinaryOperator::Max
| BinaryOperator::Min
| BinaryOperator::Step
| BinaryOperator::UniformRand => true,
| BinaryOperator::UniformRand
| BinaryOperator::Vec2 => true,
}
}
}
Expand All @@ -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(),
}
}
}
Expand Down Expand Up @@ -1630,13 +1639,20 @@ 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 {
fn to_wgsl_string(&self) -> String {
match *self {
TernaryOperator::Mix => "mix".to_string(),
TernaryOperator::SmoothStep => "smoothstep".to_string(),
TernaryOperator::Vec3 => "vec3".to_string(),
}
}
}
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 5bf400f

Please sign in to comment.