• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

djeedai / bevy_hanabi / 17622440846

10 Sep 2025 05:55PM UTC coverage: 66.033% (-0.6%) from 66.641%
17622440846

push

github

web-flow
Fixes for rustc v1.89 (#494)

Works around a bug in `encase` :
https://github.com/teoxoy/encase/issues/95

9 of 17 new or added lines in 7 files covered. (52.94%)

133 existing lines in 10 files now uncovered.

4829 of 7313 relevant lines covered (66.03%)

437.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

52.41
/src/graph/expr.rs
1
//! Expression API
2
//!
3
//! This module contains the low-level _Expression API_, designed to produce
4
//! highly customizable modifier behaviors through a code-first API focused on
5
//! runtime and serialization. For asset editing, the higher-level [Node API]
6
//! offers an easier-to-use abstraction built on top of the Expression API.
7
//!
8
//! # Modules and expressions
9
//!
10
//! A particle effect is composed of a series [`Modifier`]s decribing how to
11
//! initialize and update (simulate) the particles of the effect. Choosing which
12
//! modifier to add to an effect provides the user some limited level of
13
//! customizing. However modifiers alone cannot provide enough customizing to
14
//! build visual effects. For this reason, modifier inputs can be further
15
//! customized with _expressions_. An expression produces a value which is
16
//! assigned to the input. That value can be constant, in which case it will be
17
//! hard-coded into the generated WGSL shader, for performance reasons.
18
//! Alternatively, that value can vary based on other quantities, like an effect
19
//! property, a particle attribute, or some built-in simulation variable like
20
//! the simulation time.
21
//!
22
//! An expression is represented by the [`Expr`] enum. Expressions can be
23
//! combined together to form more complex expression; for example, the Add
24
//! expression computes the sum between two other expressions. [`Expr`]
25
//! represents a form of abstraction over the actual WGSL shader code, and is
26
//! generally closely related to the actual expressions of the WGSL language
27
//! itself.
28
//!
29
//! An expression often refers to other expressions. However, [`Expr`] as an
30
//! enum cannot directly contain other [`Expr`], otherwise the type would become
31
//! infinitely recursive. Instead, each expression is stored into a [`Module`]
32
//! and indexed by an [`ExprHandle`], a non-zero index referencing the
33
//! expression inside the module. This indirection avoids the recursion issue.
34
//! This means all expressions are implicitly associated with a unique module,
35
//! and care must be taken to not mix exressions from different modules.
36
//!
37
//! Each [`EffectAsset`] contains a single [`Module`] storing all the [`Expr`]
38
//! used in all its modifiers.
39
//!
40
//! # Kinds of expressions
41
//!
42
//! Expressions can be grouped into various kinds, for the sake of
43
//! comprehension:
44
//! - Literal expressions represent a constant, which will be hard-coded into
45
//!   the final WGSL shader code. Expressions like `1.42` or `vec3<f32>(0.)` are
46
//!   literal expressions in WGSL, and are represented by a [`LiteralExpr`].
47
//! - Built-in expressions represent specific built-in values provided by the
48
//!   simulation context. For example, the current simulation time is a built-in
49
//!   expression accessible from the shader code of any visual effect to animate
50
//!   it. A built-in expression is represented by a [`BuiltInExpr`].
51
//! - Attribute expressions represent the value of an attribute of a particle. A
52
//!   typical example is the particle position, represented by
53
//!   [`Attribute::POSITION`], which can be obtained as an expression through an
54
//!   [`AttributeExpr`].
55
//! - Property expressions represent the value of a visual effect property, a
56
//!   quantity assigned by the user on the CPU side and uploaded each frame into
57
//!   the GPU for precise per-frame control over an effect. It's represented by
58
//!   a [`PropertyExpr`].
59
//! - Unary and binary operations are expressions taking one or two operand
60
//!   expressions and transforming them. A typical example is the Add operator,
61
//!   which takes two operand expressions and produces their sum.
62
//!
63
//! # Building expressions
64
//!
65
//! The fundamental way to build expressions is to directly write them into a
66
//! [`Module`] itself. The [`Module`] type contains various methods to create
67
//! new expressions and immediately write them.
68
//!
69
//! ```
70
//! # use bevy_hanabi::*;
71
//! let mut module = Module::default();
72
//!
73
//! // Build and write a literal expression into the module.
74
//! let expr = module.lit(3.42);
75
//! ```
76
//!
77
//! Due to the code-first nature of the Expression API however, that approach
78
//! can be very verbose. Instead, users are encouraged to use an [`ExprWriter`],
79
//! a simple utility to build expressions with a shortened syntax. Once an
80
//! expression is built, it can be written into the underlying [`Module`]. This
81
//! approach generally makes the code more readable, and is therefore highly
82
//! encouraged, but is not mandatory.
83
//!
84
//! ```
85
//! # use bevy_hanabi::*;
86
//! // Create a writer owning a new Module
87
//! let mut w = ExprWriter::new();
88
//!
89
//! // Build a complex expression: max(3.42, properties.my_prop)
90
//! let prop = w.add_property("my_property", 3.0.into());
91
//! let expr = w.lit(3.42).max(w.prop(prop));
92
//!
93
//! // Finalize the expression and write it into the Module. The returned handle can
94
//! // be assign to a modifier input.
95
//! let handle = expr.expr();
96
//!
97
//! // Finish using the writer and recover the Module with all written expressions
98
//! let module = w.finish();
99
//! ```
100
//!
101
//! [Node API]: crate::graph::node
102
//! [`Modifier`]: crate::Modifier
103
//! [`EffectAsset`]: crate::EffectAsset
104

105
use std::{cell::RefCell, num::NonZeroU32, rc::Rc};
106

107
use bevy::{platform::collections::HashSet, prelude::default, reflect::Reflect};
108
use serde::{Deserialize, Serialize};
109
use thiserror::Error;
110

111
use super::Value;
112
use crate::{
113
    Attribute, ModifierContext, ParticleLayout, Property, PropertyLayout, ScalarType,
114
    TextureLayout, TextureSlot, ToWgslString, ValueType, VectorType,
115
};
116

117
/// A one-based ID into a collection of a [`Module`].
118
type Id = NonZeroU32;
119

120
/// Handle of an expression inside a given [`Module`].
121
///
122
/// A handle uniquely references an [`Expr`] stored inside a [`Module`]. It's a
123
/// lightweight representation, similar to a simple array index. For this
124
/// reason, it's easily copyable. However it's also lacking any kind of error
125
/// checking, and mixing handles to different modules produces undefined
126
/// behaviors (like an index does when indexing the wrong array).
127
#[derive(
128
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect, Serialize, Deserialize,
129
)]
130
#[repr(transparent)]
131
#[serde(transparent)]
132
pub struct ExprHandle {
133
    id: Id,
134
}
135

136
impl ExprHandle {
137
    /// Create a new handle from a 1-based [`Id`].
138
    #[allow(dead_code)]
139
    fn new(id: Id) -> Self {
×
140
        Self { id }
141
    }
142

143
    /// Create a new handle from a 1-based [`Id`] as a `usize`, for cases where
144
    /// the index is known to be non-zero already.
145
    #[allow(unsafe_code)]
146
    unsafe fn new_unchecked(id: usize) -> Self {
242✔
147
        debug_assert!(id != 0);
484✔
148
        Self {
149
            id: NonZeroU32::new_unchecked(id as u32),
242✔
150
        }
151
    }
152

153
    /// Get the zero-based index into the array of the module.
154
    fn index(&self) -> usize {
407✔
155
        (self.id.get() - 1) as usize
407✔
156
    }
157
}
158

159
/// Handle of a property inside a given [`Module`].
160
///
161
/// A handle uniquely references a [`Property`] stored inside a [`Module`]. It's
162
/// a lightweight representation, similar to a simple array index. For this
163
/// reason, it's easily copyable. However it's also lacking any kind of error
164
/// checking, and mixing handles to different modules produces undefined
165
/// behaviors (like an index does when indexing the wrong array).
166
#[derive(
167
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect, Serialize, Deserialize,
168
)]
169
#[repr(transparent)]
170
#[serde(transparent)]
171
pub struct PropertyHandle {
172
    id: Id,
173
}
174

175
impl PropertyHandle {
176
    /// Create a new handle from a 1-based [`Id`].
177
    #[allow(dead_code)]
178
    fn new(id: Id) -> Self {
×
179
        Self { id }
180
    }
181

182
    /// Create a new handle from a 1-based [`Id`] as a `usize`, for cases where
183
    /// the index is known to be non-zero already.
184
    #[allow(unsafe_code)]
185
    unsafe fn new_unchecked(id: usize) -> Self {
7✔
186
        debug_assert!(id != 0);
14✔
187
        Self {
188
            id: NonZeroU32::new_unchecked(id as u32),
7✔
189
        }
190
    }
191

192
    /// Get the zero-based index into the array of the module.
193
    fn index(&self) -> usize {
2✔
194
        (self.id.get() - 1) as usize
2✔
195
    }
196
}
197

198
/// Handle of a texture inside a given [`Module`].
199
///
200
/// A handle uniquely references a [`TextureSlot`] stored inside a [`Module`].
201
/// It's a lightweight representation, similar to a simple array index. For this
202
/// reason, it's easily copyable. However it's also lacking any kind of error
203
/// checking, and mixing handles to different modules produces undefined
204
/// behaviors (like an index does when indexing the wrong array).
205
#[derive(
206
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect, Serialize, Deserialize,
207
)]
208
#[repr(transparent)]
209
#[serde(transparent)]
210
pub struct TextureHandle {
211
    id: Id,
212
}
213

214
impl TextureHandle {
215
    /// Create a new handle from a 1-based [`Id`].
216
    #[allow(dead_code)]
217
    fn new(id: Id) -> Self {
×
218
        Self { id }
219
    }
220

221
    /// Create a new handle from a 1-based [`Id`] as a `usize`, for cases where
222
    /// the index is known to be non-zero already.
223
    #[allow(unsafe_code)]
224
    unsafe fn new_unchecked(id: usize) -> Self {
×
225
        debug_assert!(id != 0);
×
226
        Self {
227
            id: NonZeroU32::new_unchecked(id as u32),
×
228
        }
229
    }
230

231
    /// Get the zero-based index into the array of the module.
232
    #[allow(dead_code)]
233
    fn index(&self) -> usize {
×
234
        (self.id.get() - 1) as usize
×
235
    }
236
}
237

238
/// Container for expressions.
239
///
240
/// A module represents a storage for a set of expressions used in a single
241
/// [`EffectAsset`]. Modules are not reusable accross effect assets; each effect
242
/// asset owns a single module, containing all the expressions used in all the
243
/// modifiers attached to that asset. However, for convenience, a module can be
244
/// cloned into an unrelated module, and the clone can be assigned to another
245
/// effect asset.
246
///
247
/// Modules are built incrementally. Expressions are written into the module
248
/// through convenience helpers like [`lit()`] or [`attr()`]. Alternatively, an
249
/// [`ExprWriter`] can be used to populate a new or existing module. Either way,
250
/// once an expression is written into a module, it cannot be modified or
251
/// deleted. Modules are not designed to be used as editing structures, but as
252
/// storage and serialization ones.
253
///
254
/// [`EffectAsset`]: crate::EffectAsset
255
/// [`lit()`]: Module::lit
256
/// [`attr()`]: Module::attr
257
#[derive(Debug, Default, Clone, PartialEq, Hash, Reflect, Serialize, Deserialize)]
258
pub struct Module {
259
    /// Expressions defined in the module.
260
    expressions: Vec<Expr>,
261
    /// Properties used as part of a [`PropertyExpr`].
262
    properties: Vec<Property>,
263
    /// Texture layout.
264
    texture_layout: TextureLayout,
265
}
266

267
macro_rules! impl_module_unary {
268
    ($t: ident, $T: ident) => {
269
        #[doc = concat!("Build a [`UnaryOperator::", stringify!($T), "`](crate::graph::expr::UnaryOperator::", stringify!($T),") unary expression and append it to the module.\n\nThis is a shortcut for [`unary(UnaryOperator::", stringify!($T), ", inner)`](crate::graph::expr::Module::unary).")]
270
        #[inline]
271
        pub fn $t(&mut self, inner: ExprHandle) -> ExprHandle {
38✔
272
            self.unary(UnaryOperator::$T, inner)
152✔
273
        }
274
    };
275
}
276

277
macro_rules! impl_module_binary {
278
    ($t: ident, $T: ident) => {
279
        #[doc = concat!("Build a [`BinaryOperator::", stringify!($T), "`](crate::graph::expr::BinaryOperator::", stringify!($T),") binary expression and append it to the module.\n\nThis is a shortcut for [`binary(BinaryOperator::", stringify!($T), ", left, right)`](crate::graph::expr::Module::binary).")]
280
        #[inline]
281
        pub fn $t(&mut self, left: ExprHandle, right: ExprHandle) -> ExprHandle {
34✔
282
            self.binary(BinaryOperator::$T, left, right)
170✔
283
        }
284
    };
285
}
286

287
macro_rules! impl_module_ternary {
288
    ($t: ident, $T: ident) => {
289
        #[doc = concat!("Build a [`TernaryOperator::", stringify!($T), "`](crate::graph::expr::TernaryOperator::", stringify!($T),") ternary expression and append it to the module.\n\nThis is a shortcut for [`ternary(TernaryOperator::", stringify!($T), ", first, second, third)`](crate::graph::expr::Module::ternary).")]
290
        #[inline]
291
        pub fn $t(&mut self, first: ExprHandle, second: ExprHandle, third: ExprHandle) -> ExprHandle {
3✔
292
            self.ternary(TernaryOperator::$T, first, second, third)
18✔
293
        }
294
    };
295
}
296

297
impl Module {
298
    /// Create a new module from an existing collection of expressions.
299
    pub fn from_raw(expr: Vec<Expr>) -> Self {
×
300
        Self {
301
            expressions: expr,
302
            properties: vec![],
×
303
            texture_layout: default(),
×
304
        }
305
    }
306

307
    /// Add a new property to the module.
308
    ///
309
    /// See [`Property`] for more details on what effect properties are.
310
    ///
311
    /// # Panics
312
    ///
313
    /// Panics if a property with the same name already exists.
314
    pub fn add_property(
7✔
315
        &mut self,
316
        name: impl Into<String>,
317
        default_value: Value,
318
    ) -> PropertyHandle {
319
        let name = name.into();
21✔
320
        assert!(!self.properties.iter().any(|p| p.name() == name));
23✔
321
        self.properties.push(Property::new(name, default_value));
7✔
322
        // SAFETY - We just pushed a new property into the array, so its length is
323
        // non-zero.
UNCOV
324
        #[allow(unsafe_code)]
×
325
        unsafe {
UNCOV
326
            PropertyHandle::new_unchecked(self.properties.len())
×
327
        }
328
    }
329

330
    /// Get an existing property by handle.
331
    ///
332
    /// Existing properties are properties previously created with
333
    /// [`add_property()`].
334
    ///
335
    /// [`add_property()`]: crate::Module::add_property
336
    pub fn get_property(&self, property: PropertyHandle) -> Option<&Property> {
2✔
337
        self.properties.get(property.index())
6✔
338
    }
339

340
    /// Get an existing property by name.
341
    ///
342
    /// Existing properties are properties previously created with
343
    /// [`add_property()`].
344
    ///
345
    /// [`add_property()`]: crate::Module::add_property
346
    pub fn get_property_by_name(&self, name: &str) -> Option<PropertyHandle> {
×
347
        self.properties
×
348
            .iter()
349
            .enumerate()
350
            .find(|(_, prop)| prop.name() == name)
×
351
            .map(|(index, _)| PropertyHandle::new(NonZeroU32::new(index as u32 + 1).unwrap()))
×
352
    }
353

354
    /// Get the list of existing properties.
355
    pub fn properties(&self) -> &[Property] {
1,028✔
356
        &self.properties
1,028✔
357
    }
358

359
    /// Add a new texture slot to the module.
360
    ///
361
    /// The `name` parameter defines a new [`TextureSlot`] associated with this
362
    /// module, and must be unique inside this module. A unique index is also
363
    /// associated with the slot, corresponding to the value returned by
364
    /// [`TextureLayout::get_slot_by_name()`].
365
    ///
366
    /// Once a slot is added, an actual texture resource, defined by its
367
    /// `Handle<Image>`, is bound to that slot through the
368
    /// [`EffectMaterial`] component. Expressions like [`TextureSampleExpr`] can
369
    /// be used to sample the texture using the returned [`TextureHandle`].
370
    ///
371
    /// # Returns
372
    ///
373
    /// The handle of the texture inside this module. This handle is used in
374
    /// expressions like the [`TextureSampleExpr`] to reference this texture
375
    /// slot.
376
    ///
377
    /// # Panics
378
    ///
379
    /// Panics if a texture slot with the same name already exists inside this
380
    /// module. Different effect asset (different modules) can have the same
381
    /// slot name.
382
    ///
383
    /// [`EffectMaterial`]: crate::EffectMaterial
384
    pub fn add_texture_slot(&mut self, name: impl Into<String>) -> TextureHandle {
×
385
        let name = name.into();
×
386
        assert!(!self.texture_layout.layout.iter().any(|t| t.name == name));
×
387
        self.texture_layout.layout.push(TextureSlot { name });
×
388
        // SAFETY - We just pushed a new slot into the array, so its length is non-zero.
389
        #[allow(unsafe_code)]
×
390
        unsafe {
391
            TextureHandle::new_unchecked(self.texture_layout.layout.len())
×
392
        }
393
    }
394

395
    /// Insert into the given set all attributes referenced by any
396
    /// [`AttributeExpr`] present in the module.
397
    pub fn gather_attributes(&self, set: &mut HashSet<Attribute>) {
2,050✔
398
        for expr in &self.expressions {
10,152✔
399
            if let Expr::Attribute(attr) = expr {
1✔
400
                set.insert(attr.attr);
401
            }
402
        }
403
    }
404

405
    /// Append a new expression to the module.
406
    fn push(&mut self, expr: impl Into<Expr>) -> ExprHandle {
241✔
407
        self.expressions.push(expr.into());
964✔
UNCOV
408
        #[allow(unsafe_code)]
×
409
        unsafe {
410
            ExprHandle::new_unchecked(self.expressions.len())
723✔
411
        }
412
    }
413

414
    /// Build a literal expression and append it to the module.
415
    #[inline]
416
    pub fn lit<V>(&mut self, value: V) -> ExprHandle
79✔
417
    where
418
        Value: From<V>,
419
    {
420
        self.push(Expr::Literal(LiteralExpr::new(value)))
237✔
421
    }
422

423
    /// Build an attribute expression and append it to the module.
424
    #[inline]
425
    pub fn attr(&mut self, attr: Attribute) -> ExprHandle {
31✔
426
        self.push(Expr::Attribute(AttributeExpr::new(attr)))
93✔
427
    }
428

429
    /// Build a parent attribute expression and append it to the module.
430
    #[inline]
431
    pub fn parent_attr(&mut self, attr: Attribute) -> ExprHandle {
×
432
        self.push(Expr::ParentAttribute(AttributeExpr::new(attr)))
×
433
    }
434

435
    /// Build a property expression and append it to the module.
436
    ///
437
    /// A property expression retrieves the value of the given property.
438
    #[inline]
439
    pub fn prop(&mut self, property: PropertyHandle) -> ExprHandle {
3✔
440
        self.push(Expr::Property(PropertyExpr::new(property)))
9✔
441
    }
442

443
    /// Build a built-in expression and append it to the module.
444
    #[inline]
445
    pub fn builtin(&mut self, op: BuiltInOperator) -> ExprHandle {
30✔
446
        self.push(Expr::BuiltIn(BuiltInExpr::new(op)))
90✔
447
    }
448

449
    /// Build a unary expression and append it to the module.
450
    ///
451
    /// The handle to the expression representing the operand of the unary
452
    /// operation must be valid, that is reference an expression
453
    /// contained in the current [`Module`].
454
    ///
455
    /// # Panics
456
    ///
457
    /// Panics in some cases if the operand handle do not reference an existing
458
    /// expression in the current module. Note however that this check can
459
    /// miss some invalid handles (false negative), so only represents an
460
    /// extra safety net that users shouldn't rely exclusively on
461
    /// to ensure the operand handles are valid. Instead, it's the
462
    /// responsibility of the user to ensure the operand handle references an
463
    /// existing expression in the current [`Module`].
464
    #[inline]
465
    pub fn unary(&mut self, op: UnaryOperator, inner: ExprHandle) -> ExprHandle {
38✔
466
        assert!(inner.index() < self.expressions.len());
152✔
467
        self.push(Expr::Unary { op, expr: inner })
114✔
468
    }
469

470
    impl_module_unary!(abs, Abs);
471
    impl_module_unary!(acos, Acos);
472
    impl_module_unary!(asin, Asin);
473
    impl_module_unary!(atan, Atan);
474
    impl_module_unary!(all, All);
475
    impl_module_unary!(any, Any);
476
    impl_module_unary!(ceil, Ceil);
477
    impl_module_unary!(cos, Cos);
478
    impl_module_unary!(exp, Exp);
479
    impl_module_unary!(exp2, Exp2);
480
    impl_module_unary!(floor, Floor);
481
    impl_module_unary!(fract, Fract);
482
    impl_module_unary!(inverse_sqrt, InvSqrt);
483
    impl_module_unary!(length, Length);
484
    impl_module_unary!(log, Log);
485
    impl_module_unary!(log2, Log2);
486
    impl_module_unary!(normalize, Normalize);
487
    impl_module_unary!(pack4x8snorm, Pack4x8snorm);
488
    impl_module_unary!(pack4x8unorm, Pack4x8unorm);
489
    impl_module_unary!(round, Round);
490
    impl_module_unary!(saturate, Saturate);
491
    impl_module_unary!(sign, Sign);
492
    impl_module_unary!(sin, Sin);
493
    impl_module_unary!(sqrt, Sqrt);
494
    impl_module_unary!(tan, Tan);
495
    impl_module_unary!(unpack4x8snorm, Unpack4x8snorm);
496
    impl_module_unary!(unpack4x8unorm, Unpack4x8unorm);
497
    impl_module_unary!(w, W);
498
    impl_module_unary!(x, X);
499
    impl_module_unary!(y, Y);
500
    impl_module_unary!(z, Z);
501

502
    /// Build a binary expression and append it to the module.
503
    ///
504
    /// The handles to the expressions representing the left and right operands
505
    /// of the binary operation must be valid, that is reference expressions
506
    /// contained in the current [`Module`].
507
    ///
508
    /// # Panics
509
    ///
510
    /// Panics in some cases if either of the left or right operand handles do
511
    /// not reference existing expressions in the current module. Note however
512
    /// that this check can miss some invalid handles (false negative), so only
513
    /// represents an extra safety net that users shouldn't rely exclusively on
514
    /// to ensure the operand handles are valid. Instead, it's the
515
    /// responsibility of the user to ensure handles reference existing
516
    /// expressions in the current [`Module`].
517
    #[inline]
518
    pub fn binary(
34✔
519
        &mut self,
520
        op: BinaryOperator,
521
        left: ExprHandle,
522
        right: ExprHandle,
523
    ) -> ExprHandle {
524
        assert!(left.index() < self.expressions.len());
136✔
525
        assert!(right.index() < self.expressions.len());
136✔
526
        self.push(Expr::Binary { op, left, right })
136✔
527
    }
528

529
    impl_module_binary!(add, Add);
530
    impl_module_binary!(atan2, Atan2);
531
    impl_module_binary!(cross, Cross);
532
    impl_module_binary!(distance, Distance);
533
    impl_module_binary!(div, Div);
534
    impl_module_binary!(dot, Dot);
535
    impl_module_binary!(ge, GreaterThanOrEqual);
536
    impl_module_binary!(gt, GreaterThan);
537
    impl_module_binary!(le, LessThanOrEqual);
538
    impl_module_binary!(lt, LessThan);
539
    impl_module_binary!(max, Max);
540
    impl_module_binary!(min, Min);
541
    impl_module_binary!(mul, Mul);
542
    impl_module_binary!(rem, Remainder);
543
    impl_module_binary!(step, Step);
544
    impl_module_binary!(sub, Sub);
545
    impl_module_binary!(uniform, UniformRand);
546
    impl_module_binary!(normal, NormalRand);
547
    impl_module_binary!(vec2, Vec2);
548

549
    /// Build a ternary expression and append it to the module.
550
    ///
551
    /// The handles to the expressions representing the three operands of the
552
    /// ternary operation must be valid, that is reference expressions
553
    /// contained in the current [`Module`].
554
    ///
555
    /// # Panics
556
    ///
557
    /// Panics in some cases if any of the operand handles do not reference
558
    /// existing expressions in the current module. Note however
559
    /// that this check can miss some invalid handles (false negative), so only
560
    /// represents an extra safety net that users shouldn't rely exclusively on
561
    /// to ensure the operand handles are valid. Instead, it's the
562
    /// responsibility of the user to ensure handles reference existing
563
    /// expressions in the current [`Module`].
564
    #[inline]
565
    pub fn ternary(
3✔
566
        &mut self,
567
        op: TernaryOperator,
568
        first: ExprHandle,
569
        second: ExprHandle,
570
        third: ExprHandle,
571
    ) -> ExprHandle {
572
        assert!(first.index() < self.expressions.len());
12✔
573
        assert!(second.index() < self.expressions.len());
12✔
574
        assert!(third.index() < self.expressions.len());
12✔
575
        self.push(Expr::Ternary {
9✔
576
            op,
6✔
577
            first,
6✔
578
            second,
3✔
579
            third,
3✔
580
        })
581
    }
582

583
    impl_module_ternary!(mix, Mix);
584
    impl_module_ternary!(smoothstep, SmoothStep);
585

586
    /// Build a cast expression and append it to the module.
587
    ///
588
    /// The handle to the expressions representing the operand of the cast
589
    /// operation must be valid, that is reference expressions contained in
590
    /// the current [`Module`].
591
    ///
592
    /// # Panics
593
    ///
594
    /// Panics in some cases if the operand handle does not reference existing
595
    /// expressions in the current module. Note however that this check can
596
    /// miss some invalid handles (false negative), so only represents an
597
    /// extra safety net that users shouldn't rely exclusively on
598
    /// to ensure the operand handles are valid. Instead, it's the
599
    /// responsibility of the user to ensure handles reference existing
600
    /// expressions in the current [`Module`].
601
    ///
602
    /// Panics if the resulting cast expression is not valid. See
603
    /// [`CastExpr::is_valid()`] for the exact meaning.
604
    pub fn cast(&mut self, expr: ExprHandle, target: impl Into<ValueType>) -> ExprHandle {
9✔
605
        assert!(expr.index() < self.expressions.len());
36✔
606
        let target = target.into();
27✔
607
        let expr = CastExpr::new(expr, target);
36✔
608
        if let Some(valid) = expr.is_valid(self) {
27✔
609
            assert!(valid);
×
610
        }
611
        self.push(Expr::Cast(expr))
4✔
612
    }
613

614
    /// Get an existing expression from its handle.
615
    #[inline]
616
    pub fn get(&self, expr: ExprHandle) -> Option<&Expr> {
14✔
617
        let index = expr.index();
42✔
618
        self.expressions.get(index)
28✔
619
    }
620

621
    /// Get an existing expression from its handle.
622
    #[inline]
623
    pub fn get_mut(&mut self, expr: ExprHandle) -> Option<&mut Expr> {
2✔
624
        let index = expr.index();
6✔
625
        self.expressions.get_mut(index)
4✔
626
    }
627

628
    /// Get an existing expression from its handle.
629
    #[inline]
630
    pub fn try_get(&self, expr: ExprHandle) -> Result<&Expr, ExprError> {
265✔
631
        let index = expr.index();
795✔
632
        self.expressions
530✔
633
            .get(index)
265✔
634
            .ok_or(ExprError::InvalidExprHandleError(format!(
530✔
635
                "Cannot find expression with handle {:?} in the current module. Check that the Module used to build the expression was the same used in the EvalContext or the original EffectAsset.", expr)))
265✔
636
    }
637

638
    /// Get an existing expression from its handle.
639
    #[inline]
640
    pub fn try_get_mut(&mut self, expr: ExprHandle) -> Result<&mut Expr, ExprError> {
2✔
641
        let index = expr.index();
6✔
642
        self.expressions
4✔
643
            .get_mut(index)
2✔
644
            .ok_or(ExprError::InvalidExprHandleError(format!(
4✔
645
                "Cannot find expression with handle {:?} in the current module. Check that the Module used to build the expression was the same used in the EvalContext or the original EffectAsset.", expr)))
2✔
646
    }
647

648
    /// Is the expression resulting in a compile-time constant which can be
649
    /// hard-coded into a shader's code?
650
    ///
651
    /// # Panics
652
    ///
653
    /// Panics if `expr` doesn't refer to an expression of this module.
654
    #[inline]
655
    pub fn is_const(&self, expr: ExprHandle) -> bool {
×
656
        let expr = self.get(expr).unwrap();
×
657
        expr.is_const(self)
×
658
    }
659

660
    /// Has the expression any side-effect?
661
    ///
662
    /// Expressions with side-effect need to be stored into temporary variables
663
    /// when the shader code is emitted, so that the side effect is only applied
664
    /// once when the expression is reused in multiple locations.
665
    ///
666
    /// # Panics
667
    ///
668
    /// Panics if `expr` doesn't refer to an expression of this module.
669
    pub fn has_side_effect(&self, expr: ExprHandle) -> bool {
×
670
        let expr = self.get(expr).unwrap();
×
671
        expr.has_side_effect(self)
×
672
    }
673

674
    /// Get the texture layout of this module.
675
    pub fn texture_layout(&self) -> TextureLayout {
1,042✔
676
        self.texture_layout.clone()
2,084✔
677
    }
678
}
679

680
/// Errors raised when manipulating expressions [`Expr`] and node graphs
681
/// [`Graph`].
682
///
683
/// [`Graph`]: crate::graph::Graph
684
#[derive(Debug, Clone, PartialEq, Eq, Error)]
685
pub enum ExprError {
686
    /// Expression type error.
687
    ///
688
    /// Generally used for invalid type conversion (casting).
689
    #[error("Type error: {0}")]
690
    TypeError(String),
691

692
    /// Expression syntax error.
693
    #[error("Syntax error: {0}")]
694
    SyntaxError(String),
695

696
    /// Generic graph evaluation error.
697
    #[error("Graph evaluation error: {0}")]
698
    GraphEvalError(String),
699

700
    /// Error resolving a property.
701
    ///
702
    /// An unknown property was not defined in the evaluation context, which
703
    /// usually means that the property was not defined with
704
    /// [`Module::add_property()`].
705
    #[error("Property error: {0}")]
706
    PropertyError(String),
707

708
    /// Invalid expression handle not referencing any existing [`Expr`] in the
709
    /// evaluation [`Module`].
710
    ///
711
    /// This error is commonly raised when using an [`ExprWriter`] and
712
    /// forgetting to transfer the underlying [`Module`] where the expressions
713
    /// are written to the [`EffectAsset`]. See [`ExprWriter`] for details.
714
    ///
715
    /// [`EffectAsset`]: crate::EffectAsset
716
    #[error("Invalid expression handle: {0}")]
717
    InvalidExprHandleError(String),
718

719
    /// Invalid modifier context.
720
    ///
721
    /// The operation was expecting a given [`ModifierContext`], but instead
722
    /// another [`ModifierContext`] was available.
723
    #[error("Invalid modifier context {0}, expected {1} instead.")]
724
    InvalidModifierContext(ModifierContext, ModifierContext),
725
}
726

727
/// Evaluation context for transforming expressions into WGSL code.
728
///
729
/// The evaluation context references a [`Module`] storing all [`Expr`] in use,
730
/// as well as a [`ParticleLayout`] defining the existing attributes of each
731
/// particle and their layout in memory, and a [`PropertyLayout`] defining
732
/// existing properties and their layout in memory. These together define the
733
/// context within which expressions are evaluated.
734
///
735
/// A same expression can be valid in one context and invalid in another. The
736
/// most obvious example is a [`PropertyExpr`] which is only valid if the
737
/// property is actually defined in the property layout of the evaluation
738
/// context.
739
pub trait EvalContext {
740
    /// Get the modifier context of the evaluation.
741
    fn modifier_context(&self) -> ModifierContext;
742

743
    /// Get the particle layout of the effect.
744
    fn particle_layout(&self) -> &ParticleLayout;
745

746
    /// Get the property layout of the effect.
747
    fn property_layout(&self) -> &PropertyLayout;
748

749
    /// Evaluate an expression, returning its WGSL shader code.
750
    ///
751
    /// The evaluation is guaranteed to be unique. Calling `eval()` multiple
752
    /// times with the same handle will return the same result. If the
753
    /// expression referenced by `handle` has side effects, it's evaluated only
754
    /// once on first call, stored in a local variable, and the variable cached
755
    /// and returned on subsequent calls.
756
    fn eval(&mut self, module: &Module, handle: ExprHandle) -> Result<String, ExprError>;
757

758
    /// Generate a unique local variable name.
759
    ///
760
    /// Each time this function is called, a new unique name is generated. The
761
    /// name is guaranteed to be unique within the current evaluation context
762
    /// only. Do not use for global top-level identifiers.
763
    ///
764
    /// The variable name is not registered automatically in the [`Module`]. If
765
    /// you call `make_local_var()` but doesn't use the returned name, it won't
766
    /// appear in the shader.
767
    fn make_local_var(&mut self) -> String;
768

769
    /// Push an intermediate statement during an evaluation.
770
    ///
771
    /// Intermediate statements are inserted before the expression evaluation
772
    /// which produced them. They're generally used to define temporary local
773
    /// variables, for example to store the result of expressions with side
774
    /// effects.
775
    fn push_stmt(&mut self, stmt: &str);
776

777
    /// Create a function.
778
    ///
779
    /// Create a new function with the given `func_name` inside the given
780
    /// [`Module`]. The function takes a list of arguments `args`, which are
781
    /// copied verbatim into the shader code without any validation. The body of
782
    /// the function is generated by invoking the given closure once with the
783
    /// input `module` and a temporary [`EvalContext`] local to the function.
784
    /// The closure must return the generated shader code of the function
785
    /// body. Any statement pushed to the temporary function context with
786
    /// [`EvalContext::push_stmt()`] is emitted inside the function body before
787
    /// the returned code. The function can subsequently be called from the
788
    /// parent context by generating code to call `func_name`, with the correct
789
    /// arguments.
790
    fn make_fn(
791
        &mut self,
792
        func_name: &str,
793
        args: &str,
794
        module: &mut Module,
795
        f: &mut dyn FnMut(&mut Module, &mut dyn EvalContext) -> Result<String, ExprError>,
796
    ) -> Result<(), ExprError>;
797

798
    /// Check if the particle attribute struct is a pointer?
799
    ///
800
    /// In some context the attribute struct (named 'particle' in WGSL code) is
801
    /// a pointer instead of being a struct instance. This happens in particular
802
    /// when defining a function for a modifier, and passing the attribute
803
    /// struct to be modified. In that case the generated code needs to emit
804
    /// a pointer indirection code to access the fields of the struct.
805
    fn is_attribute_pointer(&self) -> bool;
806
}
807

808
/// Language expression producing a value.
809
#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)]
810
pub enum Expr {
811
    /// Built-in expression ([`BuiltInExpr`]).
812
    ///
813
    /// A built-in expression provides access to some internal
814
    /// quantities like the simulation time.
815
    BuiltIn(BuiltInExpr),
816

817
    /// Literal expression ([`LiteralExpr`]).
818
    ///
819
    /// A literal expression represents a shader constants.
820
    Literal(LiteralExpr),
821

822
    /// Property expression ([`PropertyExpr`]).
823
    ///
824
    /// A property expression represents the value of an [`EffectAsset`]'s
825
    /// property.
826
    ///
827
    /// [`EffectAsset`]: crate::EffectAsset
828
    Property(PropertyExpr),
829

830
    /// Attribute expression ([`AttributeExpr`]).
831
    ///
832
    /// An attribute expression represents the value of an attribute for a
833
    /// particle, like its position or velocity.
834
    Attribute(AttributeExpr),
835

836
    /// Attribute expression ([`AttributeExpr`]) from a parent effect.
837
    ///
838
    /// An attribute expression represents the value of an attribute for a
839
    /// particle, like its position or velocity. This attribute however refers
840
    /// to the parent particle which spawned this one, via GPU events.
841
    ///
842
    /// This attribute is only valid when used in init modifiers, from an effect
843
    /// with a parent effect (an effect which has an [`EffectParent`]
844
    /// component).
845
    ///
846
    /// [`EffectParent`]: crate::EffectParent
847
    ParentAttribute(AttributeExpr),
848

849
    /// Unary operation expression.
850
    ///
851
    /// A unary operation transforms an expression into another expression.
852
    Unary {
853
        /// Unary operator.
854
        op: UnaryOperator,
855
        /// Operand the unary operation applies to.
856
        expr: ExprHandle,
857
    },
858

859
    /// Binary operation expression.
860
    ///
861
    /// A binary operation composes two expressions into a third one.
862
    Binary {
863
        /// Binary operator.
864
        op: BinaryOperator,
865
        /// Left-hand side operand the binary operation applies to.
866
        left: ExprHandle,
867
        /// Right-hand side operand the binary operation applies to.
868
        right: ExprHandle,
869
    },
870

871
    /// Ternary operation expression.
872
    ///
873
    /// A ternary operation composes three expressions into a fourth one.
874
    Ternary {
875
        /// Ternary operator.
876
        op: TernaryOperator,
877
        /// First operand the ternary operation applies to.
878
        first: ExprHandle,
879
        /// Second operand the ternary operation applies to.
880
        second: ExprHandle,
881
        /// Third operand the ternary operation applies to.
882
        third: ExprHandle,
883
    },
884

885
    /// Cast expression.
886
    ///
887
    /// An expression to cast an expression to another type.
888
    Cast(CastExpr),
889

890
    /// Access to textures.
891
    ///
892
    /// An expression to sample a texture from the effect's material. Currently
893
    /// only color textures (returning a `vec4<f32>`) are supported.
894
    TextureSample(TextureSampleExpr),
895
}
896

897
impl Expr {
898
    /// Is the expression resulting in a compile-time constant which can be
899
    /// hard-coded into a shader's code?
900
    ///
901
    /// The [`Module`] passed as argument is the owning module of the
902
    /// expression, which is used to recursively evaluate the const-ness of the
903
    /// entire expression. For some expressions like literals or attributes or
904
    /// properties their const-ness is intrinsic to the expression type, but for
905
    /// other expressions like binary operations (addition, ...) their
906
    /// const-ness depends in turn on the const-ness of their sub-expressions
907
    /// (left and right operands), which requires a [`Module`] to be retrieved
908
    /// and evaluated.
909
    ///
910
    /// # Example
911
    ///
912
    /// ```
913
    /// # use bevy_hanabi::*;
914
    /// # let mut module = Module::default();
915
    /// // Literals are always constant by definition.
916
    /// assert!(Expr::Literal(LiteralExpr::new(1.)).is_const(&module));
917
    ///
918
    /// // Properties and attributes are never constant, since they're by definition used
919
    /// // to provide runtime customization.
920
    /// let prop = module.add_property("my_property", 3.0.into());
921
    /// assert!(!Expr::Property(PropertyExpr::new(prop)).is_const(&module));
922
    /// assert!(!Expr::Attribute(AttributeExpr::new(Attribute::POSITION)).is_const(&module));
923
    /// ```
924
    pub fn is_const(&self, module: &Module) -> bool {
×
925
        match self {
×
926
            Expr::BuiltIn(expr) => expr.is_const(),
×
927
            Expr::Literal(expr) => expr.is_const(),
×
928
            Expr::Property(expr) => expr.is_const(),
×
929
            Expr::Attribute(expr) => expr.is_const(),
×
930
            Expr::ParentAttribute(expr) => expr.is_const(),
×
931
            Expr::Unary { expr, .. } => module.is_const(*expr),
×
932
            Expr::Binary { left, right, .. } => module.is_const(*left) && module.is_const(*right),
×
933
            Expr::Ternary {
934
                first,
×
935
                second,
×
936
                third,
×
937
                ..
938
            } => module.is_const(*first) && module.is_const(*second) && module.is_const(*third),
×
939
            Expr::Cast(expr) => module.is_const(expr.inner),
×
940
            Expr::TextureSample(_) => false,
×
941
        }
942
    }
943

944
    /// Has the expression any side-effect?
945
    ///
946
    /// Expressions with side-effect need to be stored into temporary variables
947
    /// when the shader code is emitted, so that the side effect is only applied
948
    /// once when the expression is reused in multiple locations.
949
    pub fn has_side_effect(&self, module: &Module) -> bool {
×
950
        match self {
×
951
            Expr::BuiltIn(expr) => expr.has_side_effect(),
×
952
            Expr::Literal(_) => false,
×
953
            Expr::Property(_) => false,
×
954
            Expr::Attribute(_) => false,
×
955
            Expr::ParentAttribute(_) => false,
×
956
            Expr::Unary { expr, .. } => module.has_side_effect(*expr),
×
957
            Expr::Binary { left, right, op } => {
×
958
                (*op == BinaryOperator::UniformRand || *op == BinaryOperator::NormalRand)
×
959
                    || module.has_side_effect(*left)
×
960
                    || module.has_side_effect(*right)
×
961
            }
962
            Expr::Ternary {
963
                first,
×
964
                second,
×
965
                third,
×
966
                ..
967
            } => {
968
                module.has_side_effect(*first)
×
969
                    || module.has_side_effect(*second)
×
970
                    || module.has_side_effect(*third)
×
971
            }
972
            Expr::Cast(expr) => module.has_side_effect(expr.inner),
×
973
            Expr::TextureSample(_) => false,
×
974
        }
975
    }
976

977
    /// The type of the value produced by the expression.
978
    ///
979
    /// If the type is variable and depends on the runtime evaluation context,
980
    /// this returns `None`. In that case the type needs to be obtained by
981
    /// evaluating the expression with [`eval()`].
982
    ///
983
    /// # Example
984
    ///
985
    /// ```
986
    /// # use bevy_hanabi::*;
987
    /// // Literal expressions always have a constant, build-time value type.
988
    /// let expr = Expr::Literal(LiteralExpr::new(1.));
989
    /// assert_eq!(
990
    ///     expr.value_type(),
991
    ///     Some(ValueType::Scalar(ScalarType::Float))
992
    /// );
993
    /// ```
994
    ///
995
    /// [`eval()`]: crate::graph::Expr::eval
996
    pub fn value_type(&self) -> Option<ValueType> {
25✔
997
        match self {
25✔
998
            Expr::BuiltIn(expr) => Some(expr.value_type()),
×
999
            Expr::Literal(expr) => Some(expr.value_type()),
42✔
1000
            Expr::Property(_) => None,
1✔
1001
            Expr::Attribute(expr) => Some(expr.value_type()),
6✔
1002
            Expr::ParentAttribute(expr) => Some(expr.value_type()),
×
1003
            Expr::Unary { .. } => None,
×
1004
            Expr::Binary { .. } => None,
×
1005
            Expr::Ternary { .. } => None,
×
1006
            Expr::Cast(expr) => Some(expr.value_type()),
×
1007
            Expr::TextureSample(expr) => Some(expr.value_type()),
×
1008
        }
1009
    }
1010

1011
    /// Evaluate the expression in the given context.
1012
    ///
1013
    /// Evaluate the full expression as part of the given evaluation context,
1014
    /// returning the WGSL string representation of the expression on success.
1015
    ///
1016
    /// The evaluation context is used to resolve some quantities related to the
1017
    /// effect asset, like its properties. It also holds the [`Module`] that the
1018
    /// expression is part of, to allow resolving sub-expressions of operators.
1019
    ///
1020
    /// # Example
1021
    ///
1022
    /// ```
1023
    /// # use bevy_hanabi::*;
1024
    /// let mut module = Module::default();
1025
    /// # let pl = PropertyLayout::empty();
1026
    /// # let pal = ParticleLayout::default();
1027
    /// # let mut context = ShaderWriter::new(ModifierContext::Update, &pl, &pal);
1028
    /// let handle = module.lit(1.);
1029
    /// let expr = module.get(handle).unwrap();
1030
    /// assert_eq!(Ok("1.".to_string()), expr.eval(&module, &mut context));
1031
    /// ```
1032
    pub fn eval(
250✔
1033
        &self,
1034
        module: &Module,
1035
        context: &mut dyn EvalContext,
1036
    ) -> Result<String, ExprError> {
1037
        match self {
250✔
1038
            Expr::BuiltIn(expr) => expr.eval(context),
34✔
1039
            Expr::Literal(expr) => expr.eval(context),
400✔
1040
            Expr::Property(expr) => expr.eval(module, context),
10✔
1041
            Expr::Attribute(expr) => expr.eval(context, false),
120✔
1042
            Expr::ParentAttribute(expr) => expr.eval(context, true),
×
1043
            Expr::Unary { op, expr } => {
76✔
1044
                // Recursively evaluate child expressions throught the context to ensure caching
1045
                let expr = context.eval(module, *expr)?;
190✔
1046

1047
                // if expr.value_type() != self.value_type() {
1048
                //     return Err(ExprError::TypeError(format!(
1049
                //         "Cannot apply normalize() function to non-vector expression: {}",
1050
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1051
                //     )));
1052
                // }
1053

1054
                Ok(if op.is_functional() {
1055
                    format!("{}({})", op.to_wgsl_string(), expr)
136✔
1056
                } else {
1057
                    format!("{}.{}", expr, op.to_wgsl_string())
4✔
1058
                })
1059
            }
1060
            Expr::Binary { op, left, right } => {
117✔
1061
                // Recursively evaluate child expressions throught the context to ensure caching
1062
                let compiled_left = context.eval(module, *left)?;
195✔
1063
                let compiled_right = context.eval(module, *right)?;
39✔
1064

1065
                // if !self.input.value_type().is_vector() {
1066
                //     return Err(ExprError::TypeError(format!(
1067
                //         "Cannot apply normalize() function to non-vector expression: {}",
1068
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1069
                //     )));
1070
                // }
1071

1072
                if op.is_functional() {
1073
                    if op.needs_type_suffix() {
24✔
1074
                        let lhs_type = module.get(*left).and_then(|arg| arg.value_type());
×
1075
                        let rhs_type = module.get(*right).and_then(|arg| arg.value_type());
×
1076
                        if lhs_type.is_none() || rhs_type.is_none() {
×
1077
                            return Err(ExprError::TypeError(
×
1078
                                "Can't determine the type of the operand".to_string(),
×
1079
                            ));
1080
                        }
1081
                        if lhs_type != rhs_type {
1082
                            return Err(ExprError::TypeError("Mismatched types".to_string()));
×
1083
                        }
1084
                        let value_type = lhs_type.unwrap();
1085
                        let suffix = match value_type {
×
1086
                            ValueType::Scalar(ScalarType::Float) => "f",
×
1087
                            ValueType::Vector(vector_type)
×
1088
                                if vector_type.elem_type() == ScalarType::Float =>
×
1089
                            {
1090
                                match vector_type.count() {
×
1091
                                    2 => "vec2",
×
1092
                                    3 => "vec3",
×
1093
                                    4 => "vec4",
×
1094
                                    _ => unreachable!(),
1095
                                }
1096
                            }
1097
                            _ => {
1098
                                // Add more types here as needed.
1099
                                return Err(ExprError::TypeError("Unsupported type".to_string()));
×
1100
                            }
1101
                        };
1102

1103
                        Ok(format!(
1104
                            "{}_{}({}, {})",
1105
                            op.to_wgsl_string(),
1106
                            suffix,
1107
                            compiled_left,
1108
                            compiled_right
1109
                        ))
1110
                    } else {
1111
                        Ok(format!(
12✔
1112
                            "{}({}, {})",
12✔
1113
                            op.to_wgsl_string(),
12✔
1114
                            compiled_left,
12✔
1115
                            compiled_right
12✔
1116
                        ))
1117
                    }
1118
                } else {
1119
                    Ok(format!(
27✔
1120
                        "({}) {} ({})",
27✔
1121
                        compiled_left,
27✔
1122
                        op.to_wgsl_string(),
27✔
1123
                        compiled_right
27✔
1124
                    ))
1125
                }
1126
            }
1127
            Expr::Ternary {
1128
                op,
3✔
1129
                first,
3✔
1130
                second,
3✔
1131
                third,
3✔
1132
            } => {
1133
                // Recursively evaluate child expressions throught the context to ensure caching
1134
                let first = context.eval(module, *first)?;
15✔
1135
                let second = context.eval(module, *second)?;
3✔
1136
                let third = context.eval(module, *third)?;
3✔
1137

1138
                // if !self.input.value_type().is_vector() {
1139
                //     return Err(ExprError::TypeError(format!(
1140
                //         "Cannot apply normalize() function to non-vector expression: {}",
1141
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1142
                //     )));
1143
                // }
1144

1145
                Ok(format!(
1146
                    "{}({}, {}, {})",
1147
                    op.to_wgsl_string(),
1148
                    first,
1149
                    second,
1150
                    third
1151
                ))
1152
            }
1153
            Expr::Cast(expr) => {
4✔
1154
                // Recursively evaluate child expressions throught the context to ensure caching
1155
                let inner = context.eval(module, expr.inner)?;
20✔
1156

1157
                Ok(format!("{}({})", expr.target.to_wgsl_string(), inner))
1158
            }
1159
            Expr::TextureSample(expr) => expr.eval(module, context),
×
1160
        }
1161
    }
1162
}
1163

1164
/// A literal constant expression like `3.0` or `vec3<f32>(1.0, 2.0, 3.0)`.
1165
///
1166
/// Literal expression are compile-time constants. They are always constant
1167
/// ([`is_const()`] is `true`) and have a value type equal to the type of the
1168
/// constant itself.
1169
///
1170
/// [`is_const()`]: LiteralExpr::is_const
1171
#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)]
1172
#[serde(transparent)]
1173
pub struct LiteralExpr {
1174
    value: Value,
1175
}
1176

1177
impl LiteralExpr {
1178
    /// Create a new literal expression from a [`Value`].
1179
    pub fn new<V>(value: V) -> Self
80✔
1180
    where
1181
        Value: From<V>,
1182
    {
1183
        Self {
1184
            value: value.into(),
80✔
1185
        }
1186
    }
1187

1188
    /// Is the expression resulting in a compile-time constant which can be
1189
    /// hard-coded into a shader's code?
1190
    pub fn is_const(&self) -> bool {
×
1191
        true
×
1192
    }
1193

1194
    /// Get the value type of the expression.
1195
    pub fn value_type(&self) -> ValueType {
21✔
1196
        self.value.value_type()
42✔
1197
    }
1198

1199
    /// Evaluate the expression in the given context.
1200
    pub fn eval(&self, _context: &dyn EvalContext) -> Result<String, ExprError> {
100✔
1201
        Ok(self.value.to_wgsl_string())
100✔
1202
    }
1203
}
1204

1205
impl ToWgslString for LiteralExpr {
1206
    fn to_wgsl_string(&self) -> String {
×
1207
        self.value.to_wgsl_string()
×
1208
    }
1209
}
1210

1211
impl From<&Value> for LiteralExpr {
1212
    fn from(value: &Value) -> Self {
×
1213
        Self { value: *value }
×
1214
    }
1215
}
1216

1217
impl<T: Into<Value>> From<T> for LiteralExpr {
1218
    fn from(value: T) -> Self {
×
1219
        Self {
1220
            value: value.into(),
×
1221
        }
1222
    }
1223
}
1224

1225
/// Expression representing the value of an attribute of a particle.
1226
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1227
pub struct AttributeExpr {
1228
    attr: Attribute,
1229
}
1230

1231
impl AttributeExpr {
1232
    /// Create a new attribute expression.
1233
    #[inline]
1234
    pub fn new(attr: Attribute) -> Self {
32✔
1235
        Self { attr }
1236
    }
1237

1238
    /// Is the expression resulting in a compile-time constant which can be
1239
    /// hard-coded into a shader's code?
1240
    pub fn is_const(&self) -> bool {
×
1241
        false
×
1242
    }
1243

1244
    /// Get the value type of the expression.
1245
    pub fn value_type(&self) -> ValueType {
3✔
1246
        self.attr.value_type()
6✔
1247
    }
1248

1249
    /// Evaluate the expression in the given context.
1250
    pub fn eval(&self, context: &dyn EvalContext, parent: bool) -> Result<String, ExprError> {
30✔
1251
        if self.attr == Attribute::ID {
30✔
1252
            // Pseudo-attribute, not stored in the particle buffer
1253
            Ok(if parent {
×
1254
                "parent_particle_index"
×
1255
            } else {
1256
                "particle_index"
×
1257
            }
1258
            .to_string())
×
1259
        } else if self.attr == Attribute::PARTICLE_COUNTER {
30✔
1260
            // Pseudo-attribute, not stored in the particle buffer
1261
            Ok("particle_counter".to_string())
×
1262
        } else {
1263
            let owner = if parent {
30✔
1264
                "parent_particle"
×
1265
            } else {
1266
                "particle"
30✔
1267
            };
1268
            if context.is_attribute_pointer() {
1269
                Ok(format!("(*{}).{}", owner, self.attr.name()))
6✔
1270
            } else {
1271
                Ok(format!("{}.{}", owner, self.attr.name()))
28✔
1272
            }
1273
        }
1274
    }
1275
}
1276

1277
impl ToWgslString for AttributeExpr {
1278
    fn to_wgsl_string(&self) -> String {
×
1279
        format!("particle.{}", self.attr.name())
×
1280
    }
1281
}
1282

1283
impl From<Attribute> for AttributeExpr {
1284
    fn from(value: Attribute) -> Self {
×
1285
        AttributeExpr::new(value)
×
1286
    }
1287
}
1288

1289
/// Expression representing the value of a property of an effect.
1290
///
1291
/// A property expression represents the value of the property at the time the
1292
/// expression appears. In shader, the expression yields a read from the
1293
/// property memory location.
1294
///
1295
/// To create a property to reference with an expression, use
1296
/// [`Module::add_property()`].
1297
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1298
#[repr(transparent)]
1299
#[serde(transparent)]
1300
pub struct PropertyExpr {
1301
    property: PropertyHandle,
1302
}
1303

1304
impl PropertyExpr {
1305
    /// Create a new property expression.
1306
    #[inline]
1307
    pub fn new(property: PropertyHandle) -> Self {
4✔
1308
        Self { property }
1309
    }
1310

1311
    /// Is the expression resulting in a compile-time constant which can be
1312
    /// hard-coded into a shader's code?
1313
    fn is_const(&self) -> bool {
×
1314
        false
×
1315
    }
1316

1317
    /// Evaluate the expression in the given context.
1318
    fn eval(&self, module: &Module, context: &dyn EvalContext) -> Result<String, ExprError> {
2✔
1319
        let prop = module
4✔
1320
            .get_property(self.property)
4✔
1321
            .ok_or(ExprError::PropertyError(format!(
4✔
1322
                "Unknown property handle {:?} in evaluation module.",
2✔
1323
                self.property
2✔
1324
            )))?;
1325
        if !context.property_layout().contains(prop.name()) {
1326
            return Err(ExprError::PropertyError(format!(
×
1327
                "Unknown property '{}' in evaluation layout.",
×
1328
                prop.name()
×
1329
            )));
1330
        }
1331

1332
        Ok(format!("properties.{}", prop.name()))
6✔
1333
    }
1334
}
1335

1336
/// Expression to cast an expression to another type.
1337
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1338
pub struct CastExpr {
1339
    /// The operand expression to cast.
1340
    inner: ExprHandle,
1341
    /// The target type to cast to.
1342
    target: ValueType,
1343
}
1344

1345
impl CastExpr {
1346
    /// Create a new cast expression.
1347
    #[inline]
1348
    pub fn new(inner: ExprHandle, target: impl Into<ValueType>) -> Self {
12✔
1349
        Self {
1350
            inner,
1351
            target: target.into(),
12✔
1352
        }
1353
    }
1354

1355
    /// Get the value type of the expression.
1356
    pub fn value_type(&self) -> ValueType {
3✔
1357
        self.target
3✔
1358
    }
1359

1360
    /// Try to evaluate if the cast expression is valid.
1361
    ///
1362
    /// The evaluation fails if the value type of the operand cannot be
1363
    /// determined. In that case, the function returns `None`.
1364
    ///
1365
    /// Valid cast expressions are:
1366
    /// - scalar to scalar
1367
    /// - scalar to vector
1368
    /// - vector to vector
1369
    /// - matrix to matrix
1370
    pub fn is_valid(&self, module: &Module) -> Option<bool> {
12✔
1371
        let Some(inner) = module.get(self.inner) else {
36✔
1372
            return Some(false);
×
1373
        };
1374
        if let Some(inner_type) = inner.value_type() {
11✔
1375
            match self.target {
1376
                ValueType::Scalar(_) => {
1377
                    // scalar -> scalar only
1378
                    Some(matches!(inner_type, ValueType::Scalar(_)))
8✔
1379
                }
1380
                ValueType::Vector(_) => {
1381
                    // {scalar, vector} -> vector
1382
                    Some(!matches!(inner_type, ValueType::Matrix(_)))
7✔
1383
                }
1384
                ValueType::Matrix(_) => {
1385
                    // matrix -> matrix only
1386
                    Some(matches!(inner_type, ValueType::Matrix(_)))
4✔
1387
                }
1388
            }
1389
        } else {
1390
            None
1✔
1391
        }
1392
    }
1393
}
1394

1395
/// Expression to sample a texture from the effect's material.
1396
///
1397
/// This currently supports only 4-component textures sampled with [the WGSL
1398
/// `textureSample()` function], that is all textures which return a `vec4<f32>`
1399
/// when sampled. This is the case of most color textures, including
1400
/// single-channel (e.g. red) textures which return zero for missing components,
1401
/// but excludes depth textures.
1402
///
1403
/// [the WGSL `textureSample()` function]: https://www.w3.org/TR/WGSL/#texturesample
1404
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1405
pub struct TextureSampleExpr {
1406
    /// The index of the image to sample. This is the texture slot defined in
1407
    /// the [`Module`]. The texture bound to the slot is defined in the
1408
    /// [`EffectMaterial`] component.
1409
    ///
1410
    /// [`EffectMaterial`]: crate::EffectMaterial
1411
    pub image: ExprHandle,
1412
    /// The coordinates to sample at.
1413
    pub coordinates: ExprHandle,
1414
}
1415

1416
impl TextureSampleExpr {
1417
    /// Create a new texture sample expression.
1418
    #[inline]
1419
    pub fn new(image: ExprHandle, coordinates: ExprHandle) -> Self {
×
1420
        Self { image, coordinates }
1421
    }
1422

1423
    /// Get the value type of the expression.
1424
    pub fn value_type(&self) -> ValueType {
×
1425
        // FIXME - depth textures return a single f32 when sampled
1426
        ValueType::Vector(VectorType::VEC4F)
×
1427
    }
1428

1429
    /// Try to evaluate if the texture sample expression is valid.
1430
    ///
1431
    /// This only checks that the expressions exist in the module.
1432
    pub fn is_valid(&self, module: &Module) -> Option<bool> {
×
1433
        let Some(_image) = module.get(self.image) else {
×
1434
            return Some(false);
×
1435
        };
1436
        let Some(_coordinates) = module.get(self.coordinates) else {
×
1437
            return Some(false);
×
1438
        };
1439
        Some(true)
1440
    }
1441

1442
    /// Evaluate the expression in the given context.
1443
    pub fn eval(
×
1444
        &self,
1445
        module: &Module,
1446
        context: &mut dyn EvalContext,
1447
    ) -> Result<String, ExprError> {
1448
        let image = module.try_get(self.image)?;
×
1449
        let image = image.eval(module, context)?;
×
1450
        let coordinates = module.try_get(self.coordinates)?;
×
1451
        let coordinates = coordinates.eval(module, context)?;
×
1452
        Ok(format!(
1453
            "textureSample(material_texture_{image}, material_sampler_{image}, {coordinates})",
1454
        ))
1455
    }
1456
}
1457

1458
/// Built-in operators.
1459
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1460
pub enum BuiltInOperator {
1461
    /// Current effect system simulation time since startup, in seconds.
1462
    ///
1463
    /// This is based on the
1464
    /// [`Time<EffectSimulation>`](crate::time::EffectSimulation) clock.
1465
    ///
1466
    /// Type: `f32`
1467
    Time,
1468
    /// Delta time, in seconds, since last effect system update.
1469
    ///
1470
    /// Type: `f32`
1471
    DeltaTime,
1472
    /// Current virtual time since startup, in seconds.
1473
    ///
1474
    /// This is based on the [`Time<Virtual>`](bevy::time::Virtual) clock.
1475
    ///
1476
    /// Type: `f32`
1477
    VirtualTime,
1478
    /// Virtual delta time, in seconds, since last effect system update.
1479
    ///
1480
    /// Type: `f32`
1481
    VirtualDeltaTime,
1482
    /// Current real time since startup, in seconds.
1483
    ///
1484
    /// This is based on the [`Time<Time>`](bevy::time::Real) clock.
1485
    ///
1486
    /// Type: `f32`
1487
    RealTime,
1488
    /// Real delta time, in seconds, since last effect system update.
1489
    ///
1490
    /// Type: `f32`
1491
    RealDeltaTime,
1492
    /// Random unit value of the given type.
1493
    ///
1494
    /// The type can be any scalar or vector type. Matrix types are not
1495
    /// supported. The random values generated are uniformly distributed in
1496
    /// `[0:1]`. For vectors, each component is sampled separately.
1497
    ///
1498
    /// The random number generator is from [the PCG family] of PRNGs, and is
1499
    /// implemented directly inside the shader, and running on the GPU
1500
    /// exclusively. It's seeded by the [`SpawnerSettings`].
1501
    ///
1502
    /// Type: Same as its [`ValueType`].
1503
    ///
1504
    /// [the PCG family]: https://www.pcg-random.org/
1505
    /// [`SpawnerSettings`]: crate::SpawnerSettings
1506
    Rand(ValueType),
1507
    /// Value of the alpha cutoff for alpha masking.
1508
    ///
1509
    /// This value is only available in the render context. It represents the
1510
    /// current threshold, generally in \[0:1\], which the particle's fragment
1511
    /// alpha value will be compared against to determine alpha masking.
1512
    ///
1513
    /// The value is initalized at the beginning of the fragment shader to the
1514
    /// expression stored in [`AlphaMode::Mask`].
1515
    ///
1516
    /// Type: `f32`
1517
    ///
1518
    /// [`AlphaMode::Mask`]: crate::AlphaMode::Mask
1519
    AlphaCutoff,
1520
    /// Alive flag for the particle.
1521
    ///
1522
    /// The alive flag is initialized at the beginning of the update pass:
1523
    /// - If the particle has both the [`Attribute::AGE`] and
1524
    ///   [`Attribute::LIFETIME`], then the initial value at the beginning of
1525
    ///   the update pass is `age < lifetime`.
1526
    /// - Otherwise, the initial value is `true`.
1527
    ///
1528
    /// At the end of the update pass, if the particle has both the
1529
    /// [`Attribute::AGE`] and [`Attribute::LIFETIME`], then the flag is
1530
    /// re-evaluated as:
1531
    ///
1532
    /// ```wgsl
1533
    /// is_alive = is_alive && (particle.age < particle.lifetime);
1534
    /// ```
1535
    ///
1536
    /// If the flag is `false` after that, the particle is considered dead and
1537
    /// it's deallocated.
1538
    ///
1539
    /// This flag is only available in the update pass. Attempting to use it
1540
    /// inside either the init or render passes will generate an invalid shader.
1541
    ///
1542
    /// Type: `bool`
1543
    IsAlive,
1544
}
1545

1546
impl BuiltInOperator {
1547
    /// Get the operator name.
1548
    pub fn name(&self) -> &str {
49✔
1549
        match self {
49✔
1550
            BuiltInOperator::Time => "time",
6✔
1551
            BuiltInOperator::DeltaTime => "delta_time",
13✔
1552
            BuiltInOperator::VirtualTime => "virtual_time",
2✔
1553
            BuiltInOperator::VirtualDeltaTime => "virtual_delta_time",
2✔
1554
            BuiltInOperator::RealTime => "real_time",
2✔
1555
            BuiltInOperator::RealDeltaTime => "real_delta_time",
2✔
1556
            BuiltInOperator::Rand(value_type) => match value_type {
44✔
1557
                ValueType::Scalar(s) => match s {
20✔
1558
                    ScalarType::Bool => "brand",
1✔
1559
                    ScalarType::Float => "frand",
7✔
1560
                    ScalarType::Int => "irand",
1✔
1561
                    ScalarType::Uint => "urand",
1✔
1562
                },
1563
                ValueType::Vector(vector_type) => {
12✔
1564
                    match (vector_type.elem_type(), vector_type.count()) {
36✔
1565
                        (ScalarType::Bool, 2) => "brand2",
1✔
1566
                        (ScalarType::Bool, 3) => "brand3",
1✔
1567
                        (ScalarType::Bool, 4) => "brand4",
1✔
1568
                        (ScalarType::Float, 2) => "frand2",
1✔
1569
                        (ScalarType::Float, 3) => "frand3",
1✔
1570
                        (ScalarType::Float, 4) => "frand4",
1✔
1571
                        (ScalarType::Int, 2) => "irand2",
1✔
1572
                        (ScalarType::Int, 3) => "irand3",
1✔
1573
                        (ScalarType::Int, 4) => "irand4",
1✔
1574
                        (ScalarType::Uint, 2) => "urand2",
1✔
1575
                        (ScalarType::Uint, 3) => "urand3",
1✔
1576
                        (ScalarType::Uint, 4) => "urand4",
1✔
1577
                        _ => panic!("Invalid vector type {:?}", vector_type),
×
1578
                    }
1579
                }
1580
                ValueType::Matrix(_) => panic!("Invalid BuiltInOperator::Rand(ValueType::Matrix)."),
×
1581
            },
1582
            BuiltInOperator::AlphaCutoff => "alpha_cutoff",
×
1583
            BuiltInOperator::IsAlive => "is_alive",
×
1584
        }
1585
    }
1586

1587
    /// Get the type of the value of a built-in operator.
1588
    pub fn value_type(&self) -> ValueType {
4✔
1589
        match self {
4✔
1590
            BuiltInOperator::Time => ValueType::Scalar(ScalarType::Float),
2✔
1591
            BuiltInOperator::DeltaTime => ValueType::Scalar(ScalarType::Float),
2✔
1592
            BuiltInOperator::VirtualTime => ValueType::Scalar(ScalarType::Float),
×
1593
            BuiltInOperator::VirtualDeltaTime => ValueType::Scalar(ScalarType::Float),
×
1594
            BuiltInOperator::RealTime => ValueType::Scalar(ScalarType::Float),
×
1595
            BuiltInOperator::RealDeltaTime => ValueType::Scalar(ScalarType::Float),
×
1596
            BuiltInOperator::Rand(value_type) => *value_type,
×
1597
            BuiltInOperator::AlphaCutoff => ValueType::Scalar(ScalarType::Float),
×
1598
            BuiltInOperator::IsAlive => ValueType::Scalar(ScalarType::Bool),
×
1599
        }
1600
    }
1601

1602
    // /// Evaluate the result of the operator as an expression.
1603
    // pub fn eval(&self, _context: &dyn EvalContext) -> Result<String, ExprError> {
1604
    //     match self {
1605
    //         BuiltInOperator::Time => Value::Scalar(Scal)
1606
    //     }
1607
    // }
1608
}
1609

1610
impl ToWgslString for BuiltInOperator {
1611
    fn to_wgsl_string(&self) -> String {
37✔
1612
        match self {
37✔
1613
            BuiltInOperator::Rand(_) => format!("{}()", self.name()),
22✔
1614
            BuiltInOperator::IsAlive => "is_alive".to_string(),
2✔
1615
            _ => format!("sim_params.{}", self.name()),
56✔
1616
        }
1617
    }
1618
}
1619

1620
/// Expression for getting built-in quantities related to the effect system.
1621
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1622
pub struct BuiltInExpr {
1623
    operator: BuiltInOperator,
1624
}
1625

1626
impl BuiltInExpr {
1627
    /// Create a new built-in operator expression.
1628
    ///
1629
    /// # Panics
1630
    ///
1631
    /// Panics on invalid [`BuiltInOperator`], like `Rand(MatrixType)`. See
1632
    /// each [`BuiltInOperator`] variant for more details.
1633
    #[inline]
1634
    pub fn new(operator: BuiltInOperator) -> Self {
33✔
1635
        if let BuiltInOperator::Rand(value_type) = operator {
51✔
1636
            assert!(!matches!(value_type, ValueType::Matrix(_)));
18✔
1637
        }
1638
        Self { operator }
1639
    }
1640

1641
    /// Is the expression resulting in a compile-time constant?
1642
    ///
1643
    /// Constant expressions can be hard-coded into a shader's code, making them
1644
    /// more efficient and open to shader compiler optimizing.
1645
    pub fn is_const(&self) -> bool {
×
1646
        false
×
1647
    }
1648

1649
    /// Has the expression any side-effect?
1650
    ///
1651
    /// Expressions with side-effect need to be stored into temporary variables
1652
    /// when the shader code is emitted, so that the side effect is only applied
1653
    /// once when the expression is reused in multiple locations.
1654
    pub fn has_side_effect(&self) -> bool {
37✔
1655
        matches!(self.operator, BuiltInOperator::Rand(_))
52✔
1656
    }
1657

1658
    /// Get the value type of the expression.
1659
    ///
1660
    /// The value type of the expression is the type of the value(s) that an
1661
    /// expression produces.
1662
    pub fn value_type(&self) -> ValueType {
×
1663
        self.operator.value_type()
×
1664
    }
1665

1666
    /// Evaluate the expression in the given context.
1667
    pub fn eval(&self, context: &mut dyn EvalContext) -> Result<String, ExprError> {
37✔
1668
        if self.has_side_effect() {
74✔
1669
            let var_name = context.make_local_var();
66✔
1670
            context.push_stmt(&format!("let {} = {};", var_name, self.to_wgsl_string()));
110✔
1671
            Ok(var_name)
22✔
1672
        } else {
1673
            Ok(self.to_wgsl_string())
15✔
1674
        }
1675
    }
1676
}
1677

1678
impl ToWgslString for BuiltInExpr {
1679
    fn to_wgsl_string(&self) -> String {
37✔
1680
        self.operator.to_wgsl_string()
74✔
1681
    }
1682
}
1683

1684
/// Unary operator.
1685
///
1686
/// Operator applied to a single operand to produce another value. The type of
1687
/// the operand and the result are not necessarily the same. Valid operand types
1688
/// depend on the operator itself.
1689
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1690
pub enum UnaryOperator {
1691
    /// Absolute value operator.
1692
    ///
1693
    /// Return the absolute value of the operand, component-wise for vectors.
1694
    /// Only valid for numeric operands.
1695
    Abs,
1696

1697
    /// Inverse cosine operator.
1698
    ///
1699
    /// Return the inverse cosine of the operand, component-wise for vectors.
1700
    /// Only valid for floating-point operands.
1701
    Acos,
1702

1703
    /// Inverse sine operator.
1704
    ///
1705
    /// Return the inverse sine of the operand, component-wise for vectors.
1706
    /// Only valid for floating-point operands.
1707
    Asin,
1708

1709
    /// Inverse tangent operator.
1710
    ///
1711
    /// Return the inverse tangent of the operand, component-wise for vectors.
1712
    /// Only valid for floating-point operands.
1713
    Atan,
1714

1715
    /// Logical ALL operator for bool vectors.
1716
    ///
1717
    /// Return `true` if all the components of the bool vector operand are
1718
    /// `true`. Invalid for any other type of operand.
1719
    All,
1720

1721
    /// Logical ANY operator for bool vectors.
1722
    ///
1723
    /// Return `true` if any component of the bool vector operand is `true`.
1724
    /// Invalid for any other type of operand.
1725
    Any,
1726

1727
    /// Ceiling operator.
1728
    ///
1729
    /// Return the unique integral number `k` such that `k-1 < x <= k`, where
1730
    /// `x` is the operand which the operator applies to.
1731
    Ceil,
1732

1733
    /// Cosine operator.
1734
    Cos,
1735

1736
    /// Natural exponent operator.
1737
    ///
1738
    /// Return the natural exponentiation of the operand (`e^x`), component-wise
1739
    /// for vectors.
1740
    Exp,
1741

1742
    /// Base-2 exponent operator.
1743
    ///
1744
    /// Return two raised to the power of the operand (`2^x`), component-wise
1745
    /// for vectors.
1746
    Exp2,
1747

1748
    /// Floor operator.
1749
    ///
1750
    /// Return the unique integral number `k` such that `k <= x < k+1`, where
1751
    /// `x` is the operand which the operator applies to.
1752
    Floor,
1753

1754
    /// Fractional part operator.
1755
    ///
1756
    /// Return the fractional part of the operand, which is equal to `x -
1757
    /// floor(x)`, component-wise for vectors.
1758
    Fract,
1759

1760
    /// Inverse square root operator.
1761
    ///
1762
    /// Return the inverse square root of the floating-point operand (`1.0 /
1763
    /// sqrt(x)`), component-wise for vectors.
1764
    InvSqrt,
1765

1766
    /// Length operator.
1767
    ///
1768
    /// Return the length of a floating point scalar or vector. The "length" of
1769
    /// a scalar is taken as its absolute value. The length of a vector is the
1770
    /// Euclidian distance `sqrt(x^2 + ...)` (square root of the sum of the
1771
    /// squared components).
1772
    ///
1773
    /// The output is always a floating point scalar.
1774
    Length,
1775

1776
    /// Natural logarithm operator.
1777
    ///
1778
    /// Return the natural logarithm of the operand (`log(x)`), component-wise
1779
    /// for vectors.
1780
    Log,
1781

1782
    /// Base-2 logarithm operator.
1783
    ///
1784
    /// Return the base-2 logarithm of the operand (`log2(x)`), component-wise
1785
    /// for vectors.
1786
    Log2,
1787

1788
    /// Vector normalizing operator.
1789
    ///
1790
    /// Normalize the given numeric vector. Only valid for numeric vector
1791
    /// operands.
1792
    Normalize,
1793

1794
    /// Packing operator from `vec4<f32>` to `u32` (signed normalized).
1795
    ///
1796
    /// Convert the four components of a signed normalized floating point vector
1797
    /// into a signed integral `i8` value in `[-128:127]`, then pack those
1798
    /// four values into a single `u32`. Each vector component should be in
1799
    /// `[-1:1]` before packing; values outside this range are clamped.
1800
    Pack4x8snorm,
1801

1802
    /// Packing operator from `vec4<f32>` to `u32` (unsigned normalized).
1803
    ///
1804
    /// Convert the four components of an unsigned normalized floating point
1805
    /// vector into an unsigned integral `u8` value in `[0:255]`, then pack
1806
    /// those four values into a single `u32`. Each vector component should
1807
    /// be in `[0:1]` before packing; values outside this range are clamped.
1808
    Pack4x8unorm,
1809

1810
    /// Rounding operator.
1811
    ///
1812
    /// Round the given scalar of vector float to the nearest integer, returned
1813
    /// as a float value.
1814
    Round,
1815

1816
    /// Saturate operator.
1817
    ///
1818
    /// Clamp the value of the operand to the \[0:1\] range, component-wise for
1819
    /// vectors.
1820
    Saturate,
1821

1822
    /// Sign operator.
1823
    ///
1824
    /// Return a value representing the sign of a floating point scalar or
1825
    /// vector input:
1826
    /// - `1.` if the operand is > 0
1827
    /// - `0.` if the operand is = 0
1828
    /// - `-1.` if the operand is < 0
1829
    ///
1830
    /// Applies component-wise for vectors.
1831
    Sign,
1832

1833
    /// Sine operator.
1834
    Sin,
1835

1836
    /// Square root operator.
1837
    ///
1838
    /// Return the square root of the floating-point operand, component-wise for
1839
    /// vectors.
1840
    Sqrt,
1841

1842
    /// Tangent operator.
1843
    Tan,
1844

1845
    /// Unpacking operator from `u32` to `vec4<f32>` (signed normalized).
1846
    ///
1847
    /// Unpack the `u32` into four signed integral `i8` value in `[-128:127]`,
1848
    /// then convert each value to a signed normalized `f32` value in `[-1:1]`.
1849
    Unpack4x8snorm,
1850

1851
    /// Unpacking operator from `u32` to `vec4<f32>` (unsigned normalized).
1852
    ///
1853
    /// Unpack the `u32` into four unsigned integral `u8` value in `[0:255]`,
1854
    /// then convert each value to an unsigned normalized `f32` value in
1855
    /// `[0:1]`.
1856
    Unpack4x8unorm,
1857

1858
    /// Get the fourth component of a vector.
1859
    ///
1860
    /// This is only valid for vectors of rank 4.
1861
    W,
1862

1863
    /// Get the first component of a scalar or vector.
1864
    ///
1865
    /// For scalar, return the value itself. For vectors, return the first
1866
    /// component.
1867
    X,
1868

1869
    /// Get the second component of a vector.
1870
    Y,
1871

1872
    /// Get the third component of a vector.
1873
    ///
1874
    /// This is only valid for vectors of rank 3 or more.
1875
    Z,
1876
}
1877

1878
impl UnaryOperator {
1879
    /// Check if a unary operator is called via a functional-style call.
1880
    ///
1881
    /// Functional-style calls are in the form `op(inner)`, like `abs(x)` for
1882
    /// example, while non-functional ones are in the form `inner.op`,
1883
    /// like `v.x` for example. This check is used for formatting the WGSL
1884
    /// code emitted during evaluation of a binary operation expression.
1885
    pub fn is_functional(&self) -> bool {
38✔
1886
        !matches!(
34✔
1887
            *self,
38✔
1888
            UnaryOperator::X | UnaryOperator::Y | UnaryOperator::Z | UnaryOperator::W
1889
        )
1890
    }
1891
}
1892

1893
impl ToWgslString for UnaryOperator {
1894
    fn to_wgsl_string(&self) -> String {
38✔
1895
        match *self {
38✔
1896
            UnaryOperator::Abs => "abs".to_string(),
5✔
1897
            UnaryOperator::Acos => "acos".to_string(),
2✔
1898
            UnaryOperator::Asin => "asin".to_string(),
2✔
1899
            UnaryOperator::Atan => "atan".to_string(),
2✔
1900
            UnaryOperator::All => "all".to_string(),
2✔
1901
            UnaryOperator::Any => "any".to_string(),
6✔
1902
            UnaryOperator::Ceil => "ceil".to_string(),
2✔
1903
            UnaryOperator::Cos => "cos".to_string(),
2✔
1904
            UnaryOperator::Exp => "exp".to_string(),
2✔
1905
            UnaryOperator::Exp2 => "exp2".to_string(),
2✔
1906
            UnaryOperator::Floor => "floor".to_string(),
2✔
1907
            UnaryOperator::Fract => "fract".to_string(),
2✔
1908
            UnaryOperator::InvSqrt => "inverseSqrt".to_string(),
2✔
1909
            UnaryOperator::Length => "length".to_string(),
2✔
1910
            UnaryOperator::Log => "log".to_string(),
2✔
1911
            UnaryOperator::Log2 => "log2".to_string(),
2✔
1912
            UnaryOperator::Normalize => "normalize".to_string(),
4✔
1913
            UnaryOperator::Pack4x8snorm => "pack4x8snorm".to_string(),
2✔
1914
            UnaryOperator::Pack4x8unorm => "pack4x8unorm".to_string(),
2✔
1915
            UnaryOperator::Round => "round".to_string(),
2✔
1916
            UnaryOperator::Saturate => "saturate".to_string(),
2✔
1917
            UnaryOperator::Sign => "sign".to_string(),
2✔
1918
            UnaryOperator::Sin => "sin".to_string(),
2✔
1919
            UnaryOperator::Sqrt => "sqrt".to_string(),
2✔
1920
            UnaryOperator::Tan => "tan".to_string(),
2✔
1921
            UnaryOperator::Unpack4x8snorm => "unpack4x8snorm".to_string(),
2✔
1922
            UnaryOperator::Unpack4x8unorm => "unpack4x8unorm".to_string(),
2✔
1923
            UnaryOperator::W => "w".to_string(),
2✔
1924
            UnaryOperator::X => "x".to_string(),
2✔
1925
            UnaryOperator::Y => "y".to_string(),
2✔
1926
            UnaryOperator::Z => "z".to_string(),
2✔
1927
        }
1928
    }
1929
}
1930

1931
/// Binary operator.
1932
///
1933
/// Operator applied between two operands, generally denoted "left" and "right".
1934
/// The type of the operands and the result are not necessarily the same. Valid
1935
/// operand types depend on the operator itself.
1936
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1937
pub enum BinaryOperator {
1938
    /// Addition operator.
1939
    ///
1940
    /// Returns the sum of its operands. Only valid for numeric operands.
1941
    Add,
1942

1943
    /// Inverse tangent operator with 2 arguments.
1944
    ///
1945
    /// Returns the arctangent (inverse tangent) of the ratio of the first
1946
    /// argument divided by the second argument.
1947
    Atan2,
1948

1949
    /// Cross product operator.
1950
    ///
1951
    /// Returns the cross product of the left and right operands. Only valid for
1952
    /// vector type operands of size 3. Always produce a vector result of the
1953
    /// same size.
1954
    Cross,
1955

1956
    /// Distance operator.
1957
    ///
1958
    /// Returns the distance between two floating point scalar or vectors, that
1959
    /// is `length(right - left)`.
1960
    Distance,
1961

1962
    /// Division operator.
1963
    ///
1964
    /// Returns the left operand divided by the right operand. Only valid for
1965
    /// numeric operands.
1966
    Div,
1967

1968
    /// Dot product operator.
1969
    ///
1970
    /// Returns the dot product of the left and right operands. Only valid for
1971
    /// vector type operands. Always produce a scalar floating-point result.
1972
    Dot,
1973

1974
    /// Greater-than operator.
1975
    ///
1976
    /// Returns `true` if the left operand is strictly greater than the right
1977
    /// operand. Only valid for numeric types. If the operands are vectors,
1978
    /// they must be of the same rank, and the result is a bool vector of
1979
    /// that rank.
1980
    GreaterThan,
1981

1982
    /// Greater-than-or-equal operator.
1983
    ///
1984
    /// Returns `true` if the left operand is greater than or equal to the right
1985
    /// operand. Only valid for numeric types. If the operands are vectors,
1986
    /// they must be of the same rank, and the result is a bool vector of
1987
    /// that rank.
1988
    GreaterThanOrEqual,
1989

1990
    /// Less-than operator.
1991
    ///
1992
    /// Returns `true` if the left operand is strictly less than the right
1993
    /// operand. Only valid for numeric types. If the operands are vectors,
1994
    /// they must be of the same rank, and the result is a bool vector of
1995
    /// that rank.
1996
    LessThan,
1997

1998
    /// Less-than-or-equal operator.
1999
    ///
2000
    /// Returns `true` if the left operand is less than or equal to the right
2001
    /// operand. Only valid for numeric types. If the operands are vectors,
2002
    /// they must be of the same rank, and the result is a bool vector of
2003
    /// that rank.
2004
    LessThanOrEqual,
2005

2006
    /// Maximum operator.
2007
    ///
2008
    /// Returns the maximum value of its left and right operands. Only valid for
2009
    /// numeric types. If the operands are vectors, they must be of the same
2010
    /// rank, and the result is a vector of that rank and same element
2011
    /// scalar type.
2012
    Max,
2013

2014
    /// Minimum operator.
2015
    ///
2016
    /// Returns the minimum value of its left and right operands. Only valid for
2017
    /// numeric types. If the operands are vectors, they must be of the same
2018
    /// rank, and the result is a vector of that rank and same element
2019
    /// scalar type.
2020
    Min,
2021

2022
    /// Multiply operator.
2023
    ///
2024
    /// Returns the product of its operands. Only valid for numeric operands.
2025
    Mul,
2026

2027
    /// Remainder operator.
2028
    ///
2029
    /// Returns the remainder of the division of the first operand by the
2030
    /// second. Only valid for numeric types. If the operands are vectors,
2031
    /// they must be of the same rank, and the result is a vector of that
2032
    /// rank and same element scalar type.
2033
    Remainder,
2034

2035
    /// Stepping operator.
2036
    ///
2037
    /// Returns `1.0` if the left operand is less than or equal to the right
2038
    /// operand, or `0.0` otherwise. Only valid for floating scalar or vectors
2039
    /// of the same rank, and applied component-wise for vectors.
2040
    Step,
2041

2042
    /// Subtraction operator.
2043
    ///
2044
    /// Returns the difference between its left and right operands. Only valid
2045
    /// for numeric operands.
2046
    Sub,
2047

2048
    /// Uniform random number operator.
2049
    ///
2050
    /// Returns a value generated by a fast non-cryptographically-secure
2051
    /// pseudo-random number generator (PRNG) whose statistical characteristics
2052
    /// are undefined and generally focused around speed. The random value is
2053
    /// uniformly distributed between the left and right operands, which must be
2054
    /// numeric types. If the operands are vectors, they must be of the same
2055
    /// rank, and the result is a vector of that rank and same element
2056
    /// scalar type.
2057
    UniformRand,
2058

2059
    /// Normal distribution random number operator.
2060
    ///
2061
    /// Returns a value generated by a fast non-cryptographically-secure
2062
    /// pseudo-random number generator (PRNG) whose statistical characteristics
2063
    /// are undefined and generally focused around speed. The random value is
2064
    /// normally distributed with mean given by the first operand and standard
2065
    /// deviation by the second, which must be numeric types. If the operands
2066
    /// are vectors, they must be of the same rank, and the result is a vector
2067
    /// of that rank and same element scalar type.
2068
    NormalRand,
2069

2070
    /// Constructor for 2-element vectors.
2071
    ///
2072
    /// Given two scalar elements `x` and `y`, returns the vector consisting of
2073
    /// those two elements `(x, y)`.
2074
    Vec2,
2075

2076
    /// Constructor for a 4-element vector.
2077
    ///
2078
    /// Given a 3-element vector `xyz` and a scalar value `w`, returns the
2079
    /// vector `vec4(xyz, w)`.
2080
    Vec4XyzW,
2081
}
2082

2083
impl BinaryOperator {
2084
    /// Check if a binary operator is called via a functional-style call.
2085
    ///
2086
    /// Functional-style calls are in the form `op(lhs, rhs)`, like `min(a,
2087
    /// b)` for example, while non-functional ones are in the form `lhs op rhs`,
2088
    /// like `a + b` for example. This check is used for formatting the WGSL
2089
    /// code emitted during evaluation of a binary operation expression.
2090
    pub fn is_functional(&self) -> bool {
39✔
2091
        match *self {
39✔
2092
            BinaryOperator::Add
2093
            | BinaryOperator::Div
2094
            | BinaryOperator::GreaterThan
2095
            | BinaryOperator::GreaterThanOrEqual
2096
            | BinaryOperator::LessThan
2097
            | BinaryOperator::LessThanOrEqual
2098
            | BinaryOperator::Mul
2099
            | BinaryOperator::Remainder
2100
            | BinaryOperator::Sub => false,
27✔
2101
            BinaryOperator::Atan2
2102
            | BinaryOperator::Cross
2103
            | BinaryOperator::Distance
2104
            | BinaryOperator::Dot
2105
            | BinaryOperator::Max
2106
            | BinaryOperator::Min
2107
            | BinaryOperator::Step
2108
            | BinaryOperator::UniformRand
2109
            | BinaryOperator::NormalRand
2110
            | BinaryOperator::Vec2
2111
            | BinaryOperator::Vec4XyzW => true,
12✔
2112
        }
2113
    }
2114

2115
    /// Check if a binary operator needs a type suffix.
2116
    ///
2117
    /// This is currently just for `rand_uniform`
2118
    /// (`BinaryOperator::UniformRand`) and `rand_normal`
2119
    /// (`BinaryOperator::NormalRand`), which are functions we define ourselves.
2120
    /// WGSL doesn't support user-defined function overloading, so we need a
2121
    /// suffix to disambiguate the types.
2122
    pub fn needs_type_suffix(&self) -> bool {
12✔
2123
        matches!(
12✔
2124
            *self,
12✔
2125
            BinaryOperator::UniformRand | BinaryOperator::NormalRand
2126
        )
2127
    }
2128
}
2129

2130
impl ToWgslString for BinaryOperator {
2131
    fn to_wgsl_string(&self) -> String {
39✔
2132
        match *self {
39✔
2133
            BinaryOperator::Add => "+".to_string(),
5✔
2134
            BinaryOperator::Atan2 => "atan2".to_string(),
2✔
2135
            BinaryOperator::Cross => "cross".to_string(),
2✔
2136
            BinaryOperator::Distance => "distance".to_string(),
2✔
2137
            BinaryOperator::Div => "/".to_string(),
4✔
2138
            BinaryOperator::Dot => "dot".to_string(),
2✔
2139
            BinaryOperator::GreaterThan => ">".to_string(),
6✔
2140
            BinaryOperator::GreaterThanOrEqual => ">=".to_string(),
2✔
2141
            BinaryOperator::LessThan => "<".to_string(),
2✔
2142
            BinaryOperator::LessThanOrEqual => "<=".to_string(),
2✔
2143
            BinaryOperator::Max => "max".to_string(),
10✔
2144
            BinaryOperator::Min => "min".to_string(),
4✔
2145
            BinaryOperator::Mul => "*".to_string(),
12✔
2146
            BinaryOperator::Remainder => "%".to_string(),
2✔
2147
            BinaryOperator::Step => "step".to_string(),
2✔
2148
            BinaryOperator::Sub => "-".to_string(),
14✔
2149
            BinaryOperator::UniformRand => "rand_uniform".to_string(),
×
2150
            BinaryOperator::NormalRand => "rand_normal".to_string(),
×
2151
            BinaryOperator::Vec2 => "vec2".to_string(),
×
2152
            BinaryOperator::Vec4XyzW => "vec4".to_string(),
×
2153
        }
2154
    }
2155
}
2156

2157
/// Ternary operator.
2158
///
2159
/// Operator applied between three operands. The type of the operands and the
2160
/// result are not necessarily the same. Valid operand types depend on the
2161
/// operator itself.
2162
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
2163
pub enum TernaryOperator {
2164
    /// Linear blend ("mix") operator.
2165
    ///
2166
    /// Returns the linear blend between the first and second argument, based on
2167
    /// the fraction of the third argument. If the operands are vectors, they
2168
    /// must be of the same rank, and the result is a vector of that rank
2169
    /// and same element scalar type.
2170
    ///
2171
    /// The linear blend of `x` and `y` with fraction `t` is equivalent to `x *
2172
    /// (1 - t) + y * t`.
2173
    Mix,
2174

2175
    /// Smooth stepping operator.
2176
    ///
2177
    /// Returns the smooth Hermitian interpolation between the first and second
2178
    /// argument, calculated at the third argument. If the operands are vectors,
2179
    /// they must be of the same rank, and the result is a vector of that
2180
    /// rank and same element scalar type.
2181
    ///
2182
    /// The smooth stepping of `low` and `high` at position `x` is equivalent to
2183
    /// `t * t * (3. - 2. * t)` where `t = clamp((x - low) / (high - low))`
2184
    /// represents the fractional position of `x` between `low` and `high`.
2185
    ///
2186
    /// The result is always a floating point scalar in \[0:1\].
2187
    SmoothStep,
2188

2189
    /// Constructor for 3-element vectors.
2190
    ///
2191
    /// Given three scalar elements `x`, `y`, and `z`, returns the vector
2192
    /// consisting of those three elements `(x, y, z)`.
2193
    Vec3,
2194
}
2195

2196
impl ToWgslString for TernaryOperator {
2197
    fn to_wgsl_string(&self) -> String {
3✔
2198
        match *self {
3✔
2199
            TernaryOperator::Mix => "mix".to_string(),
2✔
2200
            TernaryOperator::SmoothStep => "smoothstep".to_string(),
2✔
2201
            TernaryOperator::Vec3 => "vec3".to_string(),
×
2202
        }
2203
    }
2204
}
2205

2206
/// Expression writer.
2207
///
2208
/// Utility to write expressions with a simple functional syntax. Expressions
2209
/// created with the writer are gatherned into a [`Module`] which can be
2210
/// transfered once [`finish()`]ed to initialize an [`EffectAsset`].
2211
///
2212
/// Because an [`EffectAsset`] contains a single [`Module`], you generally want
2213
/// to keep using the same [`ExprWriter`] to write all the expressions used by
2214
/// all the [`Modifer`]s assigned to a given [`EffectAsset`], and only then once
2215
/// done call [`finish()`] to recover the [`ExprWriter`]'s underlying [`Module`]
2216
/// to assign it to the [`EffectAsset`].
2217
///
2218
/// # Example
2219
///
2220
/// ```
2221
/// # use bevy_hanabi::*;
2222
/// # use bevy::prelude::*;
2223
/// // Create a writer
2224
/// let w = ExprWriter::new();
2225
///
2226
/// // Create a new expression: max(5. + particle.position, properties.my_prop)
2227
/// let prop = w.add_property("my_property", Vec3::ONE.into());
2228
/// let expr = (w.lit(5.) + w.attr(Attribute::POSITION)).max(w.prop(prop));
2229
///
2230
/// // Finalize the expression and write it down into the `Module` as an `Expr`
2231
/// let expr: ExprHandle = expr.expr();
2232
///
2233
/// // Create a modifier and assign the expression to one of its input(s)
2234
/// let init_modifier = SetAttributeModifier::new(Attribute::LIFETIME, expr);
2235
///
2236
/// // Create an EffectAsset with the modifier and the Module from the writer
2237
/// let effect = EffectAsset::new(1024, SpawnerSettings::rate(32_f32.into()), w.finish())
2238
///     .init(init_modifier);
2239
/// ```
2240
///
2241
/// [`finish()`]: ExprWriter::finish
2242
/// [`EffectAsset`]: crate::EffectAsset
2243
/// [`Modifer`]: crate::Modifier
2244
#[derive(Debug, Default, Clone)]
2245
pub struct ExprWriter {
2246
    module: Rc<RefCell<Module>>,
2247
}
2248

2249
#[allow(dead_code)]
2250
impl ExprWriter {
2251
    /// Create a new writer.
2252
    ///
2253
    /// The writer owns a new [`Module`] internally, and write all expressions
2254
    /// to it. The module can be released to the user with [`finish()`] once
2255
    /// done using the writer.
2256
    ///
2257
    /// [`finish()`]: ExprWriter::finish
2258
    pub fn new() -> Self {
3✔
2259
        Self {
2260
            module: Rc::new(RefCell::new(Module::default())),
6✔
2261
        }
2262
    }
2263

2264
    /// Create a new writer from an existing module.
2265
    ///
2266
    /// This is an advanced use entry point to write expressions into an
2267
    /// existing [`Module`]. In general, users should prefer using
2268
    /// [`ExprWriter::new()`] to create a new [`Module`], and keep using the
2269
    /// same [`ExprWriter`] to write all expressions of the same
2270
    /// [`EffectAsset`].
2271
    ///
2272
    /// [`EffectAsset`]: crate::EffectAsset
2273
    pub fn from_module(module: Rc<RefCell<Module>>) -> Self {
×
2274
        Self { module }
2275
    }
2276

2277
    /// Add a new property.
2278
    ///
2279
    /// See [`Property`] for more details on what effect properties are.
2280
    ///
2281
    /// # Panics
2282
    ///
2283
    /// Panics if a property with the same name already exists.
2284
    pub fn add_property(&self, name: impl Into<String>, default_value: Value) -> PropertyHandle {
1✔
2285
        self.module.borrow_mut().add_property(name, default_value)
3✔
2286
    }
2287

2288
    /// Push a new expression into the writer.
2289
    pub fn push(&self, expr: impl Into<Expr>) -> WriterExpr {
13✔
2290
        let expr = {
13✔
2291
            let mut m = self.module.borrow_mut();
26✔
2292
            m.push(expr.into())
39✔
2293
        };
2294
        WriterExpr {
2295
            expr,
2296
            module: Rc::clone(&self.module),
13✔
2297
        }
2298
    }
2299

2300
    /// Create a new writer expression from a literal constant.
2301
    ///
2302
    /// # Example
2303
    ///
2304
    /// ```
2305
    /// # use bevy_hanabi::*;
2306
    /// let mut w = ExprWriter::new();
2307
    /// let x = w.lit(-3.5); // x = -3.5;
2308
    /// ```
2309
    pub fn lit(&self, value: impl Into<Value>) -> WriterExpr {
11✔
2310
        self.push(Expr::Literal(LiteralExpr {
33✔
2311
            value: value.into(),
11✔
2312
        }))
2313
    }
2314

2315
    /// Create a new writer expression from an attribute.
2316
    ///
2317
    /// # Example
2318
    ///
2319
    /// ```
2320
    /// # use bevy_hanabi::*;
2321
    /// let mut w = ExprWriter::new();
2322
    /// let x = w.attr(Attribute::POSITION); // x = particle.position;
2323
    /// ```
2324
    pub fn attr(&self, attr: Attribute) -> WriterExpr {
1✔
2325
        self.push(Expr::Attribute(AttributeExpr::new(attr)))
3✔
2326
    }
2327

2328
    /// Create a new writer expression from an attribute on a parent effect.
2329
    ///
2330
    /// # Example
2331
    ///
2332
    /// ```
2333
    /// # use bevy_hanabi::*;
2334
    /// let mut w = ExprWriter::new();
2335
    /// let x = w.parent_attr(Attribute::POSITION); // x = parent_particle.position;
2336
    /// ```
2337
    pub fn parent_attr(&self, attr: Attribute) -> WriterExpr {
×
2338
        self.push(Expr::ParentAttribute(AttributeExpr::new(attr)))
×
2339
    }
2340

2341
    /// Create a new writer expression from a property.
2342
    ///
2343
    /// # Example
2344
    ///
2345
    /// ```
2346
    /// # use bevy_hanabi::*;
2347
    /// let mut w = ExprWriter::new();
2348
    /// let prop = w.add_property("my_prop", 3.0.into());
2349
    /// let x = w.prop(prop); // x = properties.my_prop;
2350
    /// ```
2351
    pub fn prop(&self, handle: PropertyHandle) -> WriterExpr {
1✔
2352
        self.push(Expr::Property(PropertyExpr::new(handle)))
3✔
2353
    }
2354

2355
    /// Create a new writer expression representing the current simulation time.
2356
    ///
2357
    /// # Example
2358
    ///
2359
    /// ```
2360
    /// # use bevy_hanabi::*;
2361
    /// let mut w = ExprWriter::new();
2362
    /// let x = w.time(); // x = sim_params.time;
2363
    /// ```
2364
    pub fn time(&self) -> WriterExpr {
×
2365
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::Time)))
×
2366
    }
2367

2368
    /// Create a new writer expression representing the simulation delta time
2369
    /// since last frame.
2370
    ///
2371
    /// # Example
2372
    ///
2373
    /// ```
2374
    /// # use bevy_hanabi::*;
2375
    /// let mut w = ExprWriter::new();
2376
    /// let x = w.delta_time(); // x = sim_params.delta_time;
2377
    /// ```
2378
    pub fn delta_time(&self) -> WriterExpr {
×
2379
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::DeltaTime)))
×
2380
    }
2381

2382
    /// Create a new writer expression representing a random value of the given
2383
    /// type.
2384
    ///
2385
    /// The type can be any scalar or vector type. Matrix types are not
2386
    /// supported. The random values generated are uniformly distributed in
2387
    /// `[0:1]`. For vectors, each component is sampled separately.
2388
    ///
2389
    /// # Panics
2390
    ///
2391
    /// Panics in the same cases as [`BuiltInExpr::new()`] does.
2392
    ///
2393
    /// # Example
2394
    ///
2395
    /// ```
2396
    /// # use bevy_hanabi::*;
2397
    /// let mut w = ExprWriter::new();
2398
    /// let x = w.rand(VectorType::VEC3F); // x = frand3();
2399
    /// ```
2400
    pub fn rand(&self, value_type: impl Into<ValueType>) -> WriterExpr {
×
2401
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::Rand(
×
2402
            value_type.into(),
×
2403
        ))))
2404
    }
2405

2406
    /// Create a new writer expression representing the alpha cutoff value used
2407
    /// for alpha masking.
2408
    ///
2409
    /// This expression is only valid when used in the context of the fragment
2410
    /// shader, in the render context.
2411
    ///
2412
    /// # Example
2413
    ///
2414
    /// ```
2415
    /// # use bevy_hanabi::*;
2416
    /// let mut w = ExprWriter::new();
2417
    /// let x = w.alpha_cutoff(); // x = alpha_cutoff;
2418
    /// ```
2419
    pub fn alpha_cutoff(&self) -> WriterExpr {
×
2420
        self.push(Expr::BuiltIn(BuiltInExpr::new(
×
2421
            BuiltInOperator::AlphaCutoff,
×
2422
        )))
2423
    }
2424

2425
    /// Finish using the writer, and recover the [`Module`] where all [`Expr`]
2426
    /// were written by the writer.
2427
    ///
2428
    /// This module is typically passed to [`EffectAsset::new()`] before adding
2429
    /// to that effect the modifiers which use the expressions created by this
2430
    /// writer.
2431
    ///
2432
    /// # Example
2433
    ///
2434
    /// ```
2435
    /// # use bevy_hanabi::*;
2436
    /// # let spawner = SpawnerSettings::default();
2437
    /// let mut w = ExprWriter::new();
2438
    /// // [...]
2439
    /// let module = w.finish();
2440
    /// let asset = EffectAsset::new(256, spawner, module);
2441
    /// ```
2442
    ///
2443
    /// [`EffectAsset::new()`]: crate::EffectAsset::new()
2444
    pub fn finish(self) -> Module {
3✔
2445
        self.module.take()
3✔
2446
    }
2447
}
2448

2449
/// Intermediate expression from an [`ExprWriter`].
2450
///
2451
/// A writer expression [`WriterExpr`] is equivalent to an [`ExprHandle`], but
2452
/// retains a reference to the underlying [`Module`] and therefore can easily be
2453
/// chained with other [`WriterExpr`] via a concise syntax, at the expense of
2454
/// being more heavyweight and locking the underlying [`Module`] under a
2455
/// ref-counted interior mutability (`Rc<RefCell<Module>>`). [`ExprHandle`] by
2456
/// opposition is a very lightweight type, similar to a simple index. And like
2457
/// an array index, [`ExprHandle`] doesn't explicitly reference its associated
2458
/// storage ([`Module`]) which needs to be remembered by the user explicitly.
2459
///
2460
/// In addition, [`WriterExpr`] implements several numerical operators like the
2461
/// [`std::ops::Add`] trait, making it simpler to combine it with another
2462
/// [`WriterExpr`].
2463
///
2464
/// ```
2465
/// # use bevy_hanabi::*;
2466
/// let mut w = ExprWriter::new();
2467
/// let x = w.lit(-3.5);
2468
/// let y = w.lit(78.);
2469
/// let z = x + y; // == 74.5
2470
/// ```
2471
///
2472
/// In general the [`WriterExpr`] type is not used directly, but inferred from
2473
/// calling [`ExprWriter`] methods and combining [`WriterExpr`] together.
2474
///
2475
/// ```
2476
/// # use bevy_hanabi::*;
2477
/// let mut w = ExprWriter::new();
2478
/// let my_prop = w.add_property("my_prop", 3.0.into());
2479
///
2480
/// // x = max(-3.5 + 1., properties.my_prop) * 0.5 - particle.position;
2481
/// let x = (w.lit(-3.5) + w.lit(1.))
2482
///     .max(w.prop(my_prop))
2483
///     .mul(w.lit(0.5))
2484
///     .sub(w.attr(Attribute::POSITION));
2485
///
2486
/// let handle: ExprHandle = x.expr();
2487
/// ```
2488
#[derive(Debug, Clone)]
2489
pub struct WriterExpr {
2490
    expr: ExprHandle,
2491
    module: Rc<RefCell<Module>>,
2492
}
2493

2494
impl WriterExpr {
2495
    fn unary_op(self, op: UnaryOperator) -> Self {
1✔
2496
        let expr = self.module.borrow_mut().push(Expr::Unary {
4✔
2497
            op,
1✔
2498
            expr: self.expr,
1✔
2499
        });
2500
        WriterExpr {
2501
            expr,
2502
            module: self.module,
1✔
2503
        }
2504
    }
2505

2506
    /// Take the absolute value of the current expression.
2507
    ///
2508
    /// This is a unary operator, which applies component-wise to vector and
2509
    /// matrix operand expressions.
2510
    ///
2511
    /// # Example
2512
    ///
2513
    /// ```
2514
    /// # use bevy_hanabi::*;
2515
    /// # let mut w = ExprWriter::new();
2516
    /// // A literal expression `x = -3.5;`.
2517
    /// let x = w.lit(-3.5);
2518
    ///
2519
    /// // The absolute value `y = abs(x);`.
2520
    /// let y = x.abs(); // == 3.5
2521
    /// ```
2522
    #[inline]
2523
    pub fn abs(self) -> Self {
1✔
2524
        self.unary_op(UnaryOperator::Abs)
3✔
2525
    }
2526

2527
    /// Apply the logical operator "all" to the current bool vector expression.
2528
    ///
2529
    /// This is a unary operator, which applies to vector operand expressions to
2530
    /// produce a scalar boolean.
2531
    ///
2532
    /// # Example
2533
    ///
2534
    /// ```
2535
    /// # use bevy_hanabi::*;
2536
    /// # use bevy::math::BVec3;
2537
    /// # let mut w = ExprWriter::new();
2538
    /// // A literal expression `x = vec3<bool>(true, false, true);`.
2539
    /// let x = w.lit(BVec3::new(true, false, true));
2540
    ///
2541
    /// // Check if all components are true `y = all(x);`.
2542
    /// let y = x.all(); // == false
2543
    /// ```
2544
    #[inline]
2545
    pub fn all(self) -> Self {
×
2546
        self.unary_op(UnaryOperator::All)
×
2547
    }
2548

2549
    /// Apply the logical operator "any" to the current bool vector expression.
2550
    ///
2551
    /// This is a unary operator, which applies to vector operand expressions to
2552
    /// produce a scalar boolean.
2553
    ///
2554
    /// # Example
2555
    ///
2556
    /// ```
2557
    /// # use bevy_hanabi::*;
2558
    /// # use bevy::math::BVec3;
2559
    /// # let mut w = ExprWriter::new();
2560
    /// // A literal expression `x = vec3<bool>(true, false, true);`.
2561
    /// let x = w.lit(BVec3::new(true, false, true));
2562
    ///
2563
    /// // Check if any components is true `y = any(x);`.
2564
    /// let y = x.any(); // == true
2565
    /// ```
2566
    #[inline]
2567
    pub fn any(self) -> Self {
×
2568
        self.unary_op(UnaryOperator::Any)
×
2569
    }
2570

2571
    /// Apply the "acos" (inverse cosine) operator to the current float scalar
2572
    /// or vector expression.
2573
    ///
2574
    /// This is a unary operator, which applies to float scalar or vector
2575
    /// operand expressions to produce a float scalar or vector. It applies
2576
    /// component-wise to vector operand expressions. The return value lies in
2577
    /// the 0 ≤ x ≤ π range.
2578
    ///
2579
    /// # Example
2580
    ///
2581
    /// ```
2582
    /// # use bevy_hanabi::*;
2583
    /// # use bevy::math::Vec3;
2584
    /// # let mut w = ExprWriter::new();
2585
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2586
    /// let x = w.lit(Vec3::ONE);
2587
    ///
2588
    /// // Acos: `y = acos(x);`
2589
    /// let y = x.acos();
2590
    /// ```
2591
    #[inline]
2592
    pub fn acos(self) -> Self {
×
2593
        self.unary_op(UnaryOperator::Acos)
×
2594
    }
2595

2596
    /// Apply the "asin" (inverse sine) operator to the current float scalar or
2597
    /// vector expression.
2598
    ///
2599
    /// This is a unary operator, which applies to float scalar or vector
2600
    /// operand expressions to produce a float scalar or vector. It applies
2601
    /// component-wise to vector operand expressions. The return value lies in
2602
    /// the -π/2 ≤ x ≤ π/2 range.
2603
    ///
2604
    /// # Example
2605
    ///
2606
    /// ```
2607
    /// # use bevy_hanabi::*;
2608
    /// # use bevy::math::Vec3;
2609
    /// # let mut w = ExprWriter::new();
2610
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2611
    /// let x = w.lit(Vec3::ONE);
2612
    ///
2613
    /// // Asin: `y = asin(x);`
2614
    /// let y = x.asin();
2615
    /// ```
2616
    #[inline]
2617
    pub fn asin(self) -> Self {
×
2618
        self.unary_op(UnaryOperator::Asin)
×
2619
    }
2620

2621
    /// Apply the "atan" (inverse tangent) operator to the current float scalar
2622
    /// or vector expression.
2623
    ///
2624
    /// This is a unary operator, which applies to float scalar or vector
2625
    /// operand expressions to produce a float scalar or vector. It applies
2626
    /// component-wise to vector operand expressions. The return value lies in
2627
    /// the -π/2 ≤ x ≤ π/2 range.
2628
    ///
2629
    /// # Example
2630
    ///
2631
    /// ```
2632
    /// # use bevy_hanabi::*;
2633
    /// # use bevy::math::Vec3;
2634
    /// # let mut w = ExprWriter::new();
2635
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2636
    /// let x = w.lit(Vec3::ONE);
2637
    ///
2638
    /// // Atan: `y = atan(x);`
2639
    /// let y = x.atan();
2640
    /// ```
2641
    #[inline]
2642
    pub fn atan(self) -> Self {
×
2643
        self.unary_op(UnaryOperator::Atan)
×
2644
    }
2645

2646
    /// Apply the "ceil" operator to the current float scalar or vector
2647
    /// expression.
2648
    ///
2649
    /// This is a unary operator, which applies to float scalar or vector
2650
    /// operand expressions to produce a float scalar or vector. It applies
2651
    /// component-wise to vector operand expressions.
2652
    ///
2653
    /// # Example
2654
    ///
2655
    /// ```
2656
    /// # use bevy_hanabi::*;
2657
    /// # use bevy::math::Vec3;
2658
    /// # let mut w = ExprWriter::new();
2659
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2660
    /// let x = w.lit(Vec3::ONE);
2661
    ///
2662
    /// // Ceil: `y = ceil(x);`
2663
    /// let y = x.ceil();
2664
    /// ```
2665
    #[inline]
2666
    pub fn ceil(self) -> Self {
×
2667
        self.unary_op(UnaryOperator::Ceil)
×
2668
    }
2669

2670
    /// Apply the "cos" operator to the current float scalar or vector
2671
    /// expression.
2672
    ///
2673
    /// This is a unary operator, which applies to float scalar or vector
2674
    /// operand expressions to produce a float scalar or vector. It applies
2675
    /// component-wise to vector operand expressions.
2676
    ///
2677
    /// # Example
2678
    ///
2679
    /// ```
2680
    /// # use bevy_hanabi::*;
2681
    /// # use bevy::math::Vec3;
2682
    /// # let mut w = ExprWriter::new();
2683
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2684
    /// let x = w.lit(Vec3::ONE);
2685
    ///
2686
    /// // Cos: `y = cos(x);`
2687
    /// let y = x.cos();
2688
    /// ```
2689
    #[inline]
2690
    pub fn cos(self) -> Self {
×
2691
        self.unary_op(UnaryOperator::Cos)
×
2692
    }
2693

2694
    /// Apply the "exp" operator to the current float scalar or vector
2695
    /// expression.
2696
    ///
2697
    /// This is a unary operator, which applies to float scalar or vector
2698
    /// operand expressions to produce a float scalar or vector. It applies
2699
    /// component-wise to vector operand expressions.
2700
    ///
2701
    /// # Example
2702
    ///
2703
    /// ```
2704
    /// # use bevy_hanabi::*;
2705
    /// # use bevy::math::Vec3;
2706
    /// # let mut w = ExprWriter::new();
2707
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2708
    /// let x = w.lit(Vec3::ONE);
2709
    ///
2710
    /// // Exp: `y = exp(x);`
2711
    /// let y = x.exp();
2712
    /// ```
2713
    #[inline]
2714
    pub fn exp(self) -> Self {
×
2715
        self.unary_op(UnaryOperator::Exp)
×
2716
    }
2717

2718
    /// Apply the "exp2" operator to the current float scalar or vector
2719
    /// expression.
2720
    ///
2721
    /// This is a unary operator, which applies to float scalar or vector
2722
    /// operand expressions to produce a float scalar or vector. It applies
2723
    /// component-wise to vector operand expressions.
2724
    ///
2725
    /// # Example
2726
    ///
2727
    /// ```
2728
    /// # use bevy_hanabi::*;
2729
    /// # use bevy::math::Vec3;
2730
    /// # let mut w = ExprWriter::new();
2731
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2732
    /// let x = w.lit(Vec3::ONE);
2733
    ///
2734
    /// // Exp2: `y = exp2(x);`
2735
    /// let y = x.exp2();
2736
    /// ```
2737
    #[inline]
2738
    pub fn exp2(self) -> Self {
×
2739
        self.unary_op(UnaryOperator::Exp2)
×
2740
    }
2741

2742
    /// Apply the "floor" operator to the current float scalar or vector
2743
    /// expression.
2744
    ///
2745
    /// This is a unary operator, which applies to float scalar or vector
2746
    /// operand expressions to produce a float scalar or vector. It applies
2747
    /// component-wise to vector operand expressions.
2748
    ///
2749
    /// # Example
2750
    ///
2751
    /// ```
2752
    /// # use bevy_hanabi::*;
2753
    /// # use bevy::math::Vec3;
2754
    /// # let mut w = ExprWriter::new();
2755
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2756
    /// let x = w.lit(Vec3::ONE);
2757
    ///
2758
    /// // Floor: `y = floor(x);`
2759
    /// let y = x.floor();
2760
    /// ```
2761
    #[inline]
2762
    pub fn floor(self) -> Self {
×
2763
        self.unary_op(UnaryOperator::Floor)
×
2764
    }
2765

2766
    /// Apply the "fract" operator to the current float scalar or vector
2767
    /// expression.
2768
    ///
2769
    /// This is a unary operator, which applies to float scalar or vector
2770
    /// operand expressions to produce a float scalar or vector. It applies
2771
    /// component-wise to vector operand expressions.
2772
    ///
2773
    /// # Example
2774
    ///
2775
    /// ```
2776
    /// # use bevy_hanabi::*;
2777
    /// # use bevy::math::Vec3;
2778
    /// # let mut w = ExprWriter::new();
2779
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2780
    /// let x = w.lit(Vec3::ONE);
2781
    ///
2782
    /// // Fract: `y = fract(x);`
2783
    /// let y = x.fract();
2784
    /// ```
2785
    #[inline]
2786
    pub fn fract(self) -> Self {
×
2787
        self.unary_op(UnaryOperator::Fract)
×
2788
    }
2789

2790
    /// Apply the "inverseSqrt" (inverse square root) operator to the current
2791
    /// float scalar or vector expression.
2792
    ///
2793
    /// This is a unary operator, which applies to float scalar or vector
2794
    /// operand expressions to produce a float scalar or vector. It applies
2795
    /// component-wise to vector operand expressions.
2796
    ///
2797
    /// # Example
2798
    ///
2799
    /// ```
2800
    /// # use bevy_hanabi::*;
2801
    /// # use bevy::math::Vec3;
2802
    /// # let mut w = ExprWriter::new();
2803
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2804
    /// let x = w.lit(Vec3::ONE);
2805
    ///
2806
    /// // Inverse square root: `y = inverseSqrt(x) = 1.0 / sqrt(x);`
2807
    /// let y = x.inverse_sqrt();
2808
    /// ```
2809
    #[inline]
2810
    pub fn inverse_sqrt(self) -> Self {
×
2811
        self.unary_op(UnaryOperator::InvSqrt)
×
2812
    }
2813

2814
    /// Apply the "length" operator to the current float scalar or vector
2815
    /// expression.
2816
    ///
2817
    /// This is a unary operator, which applies to float scalar or vector
2818
    /// operand expressions to produce a float scalar or vector. It applies
2819
    /// component-wise to vector operand expressions.
2820
    ///
2821
    /// # Example
2822
    ///
2823
    /// ```
2824
    /// # use bevy_hanabi::*;
2825
    /// # use bevy::math::Vec3;
2826
    /// # let mut w = ExprWriter::new();
2827
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2828
    /// let x = w.lit(Vec3::ONE);
2829
    ///
2830
    /// // Length: `y = length(x);`
2831
    /// let y = x.length();
2832
    /// ```
2833
    #[inline]
2834
    pub fn length(self) -> Self {
×
2835
        self.unary_op(UnaryOperator::Length)
×
2836
    }
2837

2838
    /// Apply the "log" operator to the current float scalar or vector
2839
    /// expression.
2840
    ///
2841
    /// This is a unary operator, which applies to float scalar or vector
2842
    /// operand expressions to produce a float scalar or vector. It applies
2843
    /// component-wise to vector operand expressions.
2844
    ///
2845
    /// # Example
2846
    ///
2847
    /// ```
2848
    /// # use bevy_hanabi::*;
2849
    /// # use bevy::math::Vec3;
2850
    /// # let mut w = ExprWriter::new();
2851
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2852
    /// let x = w.lit(Vec3::ONE);
2853
    ///
2854
    /// // Log: `y = log(x);`
2855
    /// let y = x.log();
2856
    /// ```
2857
    #[inline]
2858
    pub fn log(self) -> Self {
×
2859
        self.unary_op(UnaryOperator::Log)
×
2860
    }
2861

2862
    /// Apply the "log2" operator to the current float scalar or vector
2863
    /// expression.
2864
    ///
2865
    /// This is a unary operator, which applies to float scalar or vector
2866
    /// operand expressions to produce a float scalar or vector. It applies
2867
    /// component-wise to vector operand expressions.
2868
    ///
2869
    /// # Example
2870
    ///
2871
    /// ```
2872
    /// # use bevy_hanabi::*;
2873
    /// # use bevy::math::Vec3;
2874
    /// # let mut w = ExprWriter::new();
2875
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2876
    /// let x = w.lit(Vec3::ONE);
2877
    ///
2878
    /// // Log2: `y = log2(x);`
2879
    /// let y = x.log2();
2880
    /// ```
2881
    #[inline]
2882
    pub fn log2(self) -> Self {
×
2883
        self.unary_op(UnaryOperator::Log2)
×
2884
    }
2885

2886
    /// Apply the "normalize" operator to the current float vector expression.
2887
    ///
2888
    /// This is a unary operator, which applies to float vector operand
2889
    /// expressions to produce another float vector with unit length
2890
    /// (normalized).
2891
    ///
2892
    /// # Example
2893
    ///
2894
    /// ```
2895
    /// # use bevy_hanabi::*;
2896
    /// # use bevy::math::Vec3;
2897
    /// # let mut w = ExprWriter::new();
2898
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2899
    /// let x = w.lit(Vec3::ONE);
2900
    ///
2901
    /// // Normalize: `y = normalize(x);`
2902
    /// let y = x.normalized();
2903
    /// ```
2904
    #[inline]
2905
    pub fn normalized(self) -> Self {
×
2906
        self.unary_op(UnaryOperator::Normalize)
×
2907
    }
2908

2909
    /// Apply the "pack4x8snorm" operator to the current 4-component float
2910
    /// vector expression.
2911
    ///
2912
    /// This is a unary operator, which applies to 4-component float vector
2913
    /// operand expressions to produce a single `u32` scalar expression.
2914
    ///
2915
    /// # Example
2916
    ///
2917
    /// ```
2918
    /// # use bevy_hanabi::*;
2919
    /// # use bevy::math::Vec4;
2920
    /// # let mut w = ExprWriter::new();
2921
    /// // A literal expression `x = vec4<f32>(-1., 1., 0., 7.2);`.
2922
    /// let x = w.lit(Vec4::new(-1., 1., 0., 7.2));
2923
    ///
2924
    /// // Pack: `y = pack4x8snorm(x);`
2925
    /// let y = x.pack4x8snorm(); // 0x7F007FFFu32
2926
    /// ```
2927
    #[inline]
2928
    pub fn pack4x8snorm(self) -> Self {
×
2929
        self.unary_op(UnaryOperator::Pack4x8snorm)
×
2930
    }
2931

2932
    /// Apply the "pack4x8unorm" operator to the current 4-component float
2933
    /// vector expression.
2934
    ///
2935
    /// This is a unary operator, which applies to 4-component float vector
2936
    /// operand expressions to produce a single `u32` scalar expression.
2937
    ///
2938
    /// # Example
2939
    ///
2940
    /// ```
2941
    /// # use bevy_hanabi::*;
2942
    /// # use bevy::math::Vec4;
2943
    /// # let mut w = ExprWriter::new();
2944
    /// // A literal expression `x = vec4<f32>(-1., 1., 0., 7.2);`.
2945
    /// let x = w.lit(Vec4::new(-1., 1., 0., 7.2));
2946
    ///
2947
    /// // Pack: `y = pack4x8unorm(x);`
2948
    /// let y = x.pack4x8unorm(); // 0xFF00FF00u32
2949
    /// ```
2950
    #[inline]
2951
    pub fn pack4x8unorm(self) -> Self {
×
2952
        self.unary_op(UnaryOperator::Pack4x8unorm)
×
2953
    }
2954

2955
    /// Apply the "round" operator to the current float scalar or vector
2956
    /// expression.
2957
    ///
2958
    /// This is a unary operator, which applies to float scalar or vector
2959
    /// operand expressions to produce a float scalar or vector. It applies
2960
    /// component-wise to vector operand expressions.
2961
    ///
2962
    /// # Example
2963
    ///
2964
    /// ```
2965
    /// # use bevy_hanabi::*;
2966
    /// # use bevy::math::Vec3;
2967
    /// # let mut w = ExprWriter::new();
2968
    /// // A literal expression `x = vec3<f32>(1.5, -3.2, 0.75);`.
2969
    /// let x = w.lit(Vec3::new(1.5, -3.2, 0.75));
2970
    ///
2971
    /// // Sign: `y = round(x);`
2972
    /// let y = x.round();
2973
    /// ```
2974
    #[inline]
2975
    pub fn round(self) -> Self {
×
2976
        self.unary_op(UnaryOperator::Round)
×
2977
    }
2978

2979
    /// Apply the "sign" operator to the current float scalar or vector
2980
    /// expression.
2981
    ///
2982
    /// This is a unary operator, which applies to float scalar or vector
2983
    /// operand expressions to produce a float scalar or vector. It applies
2984
    /// component-wise to vector operand expressions.
2985
    ///
2986
    /// # Example
2987
    ///
2988
    /// ```
2989
    /// # use bevy_hanabi::*;
2990
    /// # use bevy::math::Vec3;
2991
    /// # let mut w = ExprWriter::new();
2992
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2993
    /// let x = w.lit(Vec3::ONE);
2994
    ///
2995
    /// // Sign: `y = sign(x);`
2996
    /// let y = x.sign();
2997
    /// ```
2998
    #[inline]
2999
    pub fn sign(self) -> Self {
×
3000
        self.unary_op(UnaryOperator::Sign)
×
3001
    }
3002

3003
    /// Apply the "sin" operator to the current float scalar or vector
3004
    /// expression.
3005
    ///
3006
    /// This is a unary operator, which applies to float scalar or vector
3007
    /// operand expressions to produce a float scalar or vector. It applies
3008
    /// component-wise to vector operand expressions.
3009
    ///
3010
    /// # Example
3011
    ///
3012
    /// ```
3013
    /// # use bevy_hanabi::*;
3014
    /// # use bevy::math::Vec3;
3015
    /// # let mut w = ExprWriter::new();
3016
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3017
    /// let x = w.lit(Vec3::ONE);
3018
    ///
3019
    /// // Sin: `y = sin(x);`
3020
    /// let y = x.sin();
3021
    /// ```
3022
    #[inline]
3023
    pub fn sin(self) -> Self {
×
3024
        self.unary_op(UnaryOperator::Sin)
×
3025
    }
3026

3027
    /// Apply the "sqrt" (square root) operator to the current float scalar or
3028
    /// vector expression.
3029
    ///
3030
    /// This is a unary operator, which applies to float scalar or vector
3031
    /// operand expressions to produce a float scalar or vector. It applies
3032
    /// component-wise to vector operand expressions.
3033
    ///
3034
    /// # Example
3035
    ///
3036
    /// ```
3037
    /// # use bevy_hanabi::*;
3038
    /// # use bevy::math::Vec3;
3039
    /// # let mut w = ExprWriter::new();
3040
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3041
    /// let x = w.lit(Vec3::ONE);
3042
    ///
3043
    /// // Square root: `y = sqrt(x);`
3044
    /// let y = x.sqrt();
3045
    /// ```
3046
    #[inline]
3047
    pub fn sqrt(self) -> Self {
×
3048
        self.unary_op(UnaryOperator::Sqrt)
×
3049
    }
3050

3051
    /// Apply the "tan" operator to the current float scalar or vector
3052
    /// expression.
3053
    ///
3054
    /// This is a unary operator, which applies to float scalar or vector
3055
    /// operand expressions to produce a float scalar or vector. It applies
3056
    /// component-wise to vector operand expressions.
3057
    ///
3058
    /// # Example
3059
    ///
3060
    /// ```
3061
    /// # use bevy_hanabi::*;
3062
    /// # use bevy::math::Vec3;
3063
    /// # let mut w = ExprWriter::new();
3064
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3065
    /// let x = w.lit(Vec3::ONE);
3066
    ///
3067
    /// // Tan: `y = tan(x);`
3068
    /// let y = x.tan();
3069
    /// ```
3070
    #[inline]
3071
    pub fn tan(self) -> Self {
×
3072
        self.unary_op(UnaryOperator::Tan)
×
3073
    }
3074

3075
    /// Apply the "unpack4x8snorm" operator to the current `u32` scalar
3076
    /// expression.
3077
    ///
3078
    /// This is a unary operator, which applies to `u32` scalar operand
3079
    /// expressions to produce a 4-component floating point vector of signed
3080
    /// normalized components in `[-1:1]`.
3081
    ///
3082
    /// # Example
3083
    ///
3084
    /// ```
3085
    /// # use bevy_hanabi::*;
3086
    /// # use bevy::math::Vec3;
3087
    /// # let mut w = ExprWriter::new();
3088
    /// // A literal expression `y = 0x7F007FFFu32;`.
3089
    /// let y = w.lit(0x7F007FFFu32);
3090
    ///
3091
    /// // Unpack: `x = unpack4x8snorm(y);`
3092
    /// let x = y.unpack4x8snorm(); // vec4<f32>(-1., 1., 0., 7.2)
3093
    /// ```
3094
    #[inline]
3095
    pub fn unpack4x8snorm(self) -> Self {
×
3096
        self.unary_op(UnaryOperator::Unpack4x8snorm)
×
3097
    }
3098

3099
    /// Apply the "unpack4x8unorm" operator to the current `u32` scalar
3100
    /// expression.
3101
    ///
3102
    /// This is a unary operator, which applies to `u32` scalar operand
3103
    /// expressions to produce a 4-component floating point vector of unsigned
3104
    /// normalized components in `[0:1]`.
3105
    ///
3106
    /// # Example
3107
    ///
3108
    /// ```
3109
    /// # use bevy_hanabi::*;
3110
    /// # use bevy::math::Vec3;
3111
    /// # let mut w = ExprWriter::new();
3112
    /// // A literal expression `y = 0xFF00FF00u32;`.
3113
    /// let y = w.lit(0xFF00FF00u32);
3114
    ///
3115
    /// // Unpack: `x = unpack4x8unorm(y);`
3116
    /// let x = y.unpack4x8unorm(); // vec4<f32>(-1., 1., 0., 7.2)
3117
    /// ```
3118
    #[inline]
3119
    pub fn unpack4x8unorm(self) -> Self {
×
3120
        self.unary_op(UnaryOperator::Unpack4x8unorm)
×
3121
    }
3122

3123
    /// Apply the "saturate" operator to the current float scalar or vector
3124
    /// expression.
3125
    ///
3126
    /// This is a unary operator, which applies to float scalar or vector
3127
    /// operand expressions to produce a float scalar or vector. It applies
3128
    /// component-wise to vector operand expressions.
3129
    ///
3130
    /// # Example
3131
    ///
3132
    /// ```
3133
    /// # use bevy_hanabi::*;
3134
    /// # use bevy::math::Vec3;
3135
    /// # let mut w = ExprWriter::new();
3136
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3137
    /// let x = w.lit(Vec3::ONE);
3138
    ///
3139
    /// // Saturate: `y = saturate(x);`
3140
    /// let y = x.saturate();
3141
    /// ```
3142
    #[inline]
3143
    pub fn saturate(self) -> Self {
×
3144
        self.unary_op(UnaryOperator::Saturate)
×
3145
    }
3146

3147
    /// Get the first component of a scalar or vector.
3148
    ///
3149
    /// # Example
3150
    ///
3151
    /// ```
3152
    /// # use bevy_hanabi::*;
3153
    /// # use bevy::math::Vec3;
3154
    /// # let mut w = ExprWriter::new();
3155
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3156
    /// let v = w.lit(Vec3::ONE);
3157
    ///
3158
    /// // f = v.x;`
3159
    /// let f = v.x();
3160
    /// ```
3161
    #[inline]
3162
    pub fn x(self) -> Self {
×
3163
        self.unary_op(UnaryOperator::X)
×
3164
    }
3165

3166
    /// Get the second component of a vector.
3167
    ///
3168
    /// # Example
3169
    ///
3170
    /// ```
3171
    /// # use bevy_hanabi::*;
3172
    /// # use bevy::math::Vec3;
3173
    /// # let mut w = ExprWriter::new();
3174
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3175
    /// let v = w.lit(Vec3::ONE);
3176
    ///
3177
    /// // f = v.y;`
3178
    /// let f = v.y();
3179
    /// ```
3180
    #[inline]
3181
    pub fn y(self) -> Self {
×
3182
        self.unary_op(UnaryOperator::Y)
×
3183
    }
3184

3185
    /// Get the third component of a vector.
3186
    ///
3187
    /// # Example
3188
    ///
3189
    /// ```
3190
    /// # use bevy_hanabi::*;
3191
    /// # use bevy::math::Vec3;
3192
    /// # let mut w = ExprWriter::new();
3193
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3194
    /// let v = w.lit(Vec3::ONE);
3195
    ///
3196
    /// // f = v.z;`
3197
    /// let f = v.z();
3198
    /// ```
3199
    #[inline]
3200
    pub fn z(self) -> Self {
×
3201
        self.unary_op(UnaryOperator::Z)
×
3202
    }
3203

3204
    /// Get the fourth component of a vector.
3205
    ///
3206
    /// # Example
3207
    ///
3208
    /// ```
3209
    /// # use bevy_hanabi::*;
3210
    /// # use bevy::math::Vec3;
3211
    /// # let mut w = ExprWriter::new();
3212
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3213
    /// let v = w.lit(Vec3::ONE);
3214
    ///
3215
    /// // f = v.w;`
3216
    /// let f = v.w();
3217
    /// ```
3218
    #[inline]
3219
    pub fn w(self) -> Self {
×
3220
        self.unary_op(UnaryOperator::W)
×
3221
    }
3222

3223
    fn binary_op(self, other: Self, op: BinaryOperator) -> Self {
5✔
3224
        assert_eq!(self.module, other.module);
5✔
3225
        let left = self.expr;
10✔
3226
        let right = other.expr;
10✔
3227
        let expr = self
15✔
3228
            .module
10✔
3229
            .borrow_mut()
3230
            .push(Expr::Binary { op, left, right });
15✔
3231
        WriterExpr {
3232
            expr,
3233
            module: self.module,
5✔
3234
        }
3235
    }
3236

3237
    /// Add the current expression with another expression.
3238
    ///
3239
    /// This is a binary operator, which applies component-wise to vector
3240
    /// operand expressions.
3241
    ///
3242
    /// You can also use the [`std::ops::Add`] trait directly, via the `+`
3243
    /// symbol, as an alternative to calling this method directly.
3244
    ///
3245
    /// # Example
3246
    ///
3247
    /// ```
3248
    /// # use bevy_hanabi::*;
3249
    /// # use bevy::math::Vec2;
3250
    /// # let mut w = ExprWriter::new();
3251
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3252
    /// let x = w.lit(Vec2::new(3., -2.));
3253
    ///
3254
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3255
    /// let y = w.lit(Vec2::new(1., 5.));
3256
    ///
3257
    /// // The sum of both vectors `z = x + y;`.
3258
    /// let z = x.add(y); // == vec2<f32>(4., 3.)
3259
    ///                   // -OR-
3260
    ///                   // let z = x + y;
3261
    /// ```
3262
    #[allow(clippy::should_implement_trait)]
3263
    #[inline]
3264
    pub fn add(self, other: Self) -> Self {
2✔
3265
        self.binary_op(other, BinaryOperator::Add)
8✔
3266
    }
3267

3268
    /// Apply the "atan2" (inverse tangent with 2 arguments) operator to the
3269
    /// current float scalar or vector expression.
3270
    ///
3271
    /// This is a unary operator, which applies to float scalar or vector
3272
    /// operand expressions to produce a float scalar or vector. It applies
3273
    /// component-wise to vector operand expressions. The return value lies in
3274
    /// the -π ≤ x ≤ π range, and represents a value whose tangent is equal to
3275
    /// y over x (`z = atan2(y, x)` <=> `tan(z) = y / x`).
3276
    ///
3277
    /// # Example
3278
    ///
3279
    /// ```
3280
    /// # use bevy_hanabi::*;
3281
    /// # use bevy::math::Vec3;
3282
    /// # let mut w = ExprWriter::new();
3283
    /// // Two literal expressions `x` and `y`.
3284
    /// let x = w.lit(Vec3::new(1., 0., -1.));
3285
    /// let y = w.lit(Vec3::ONE);
3286
    ///
3287
    /// // Atan: `z = atan2(y, x);`
3288
    /// let z = y.atan2(x);
3289
    /// ```
3290
    #[inline]
3291
    pub fn atan2(self, other: Self) -> Self {
×
3292
        self.binary_op(other, BinaryOperator::Atan2)
×
3293
    }
3294

3295
    /// Calculate the cross product of the current expression by another
3296
    /// expression.
3297
    ///
3298
    /// This is a binary operator, which applies to vector operands of size 3
3299
    /// only, and always produces a vector of the same size.
3300
    ///
3301
    /// # Example
3302
    ///
3303
    /// ```
3304
    /// # use bevy_hanabi::*;
3305
    /// # use bevy::math::Vec3;
3306
    /// # let mut w = ExprWriter::new();
3307
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3308
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3309
    ///
3310
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3311
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3312
    ///
3313
    /// // The cross product of both vectors `z = cross(x, y);`.
3314
    /// let z = x.cross(y);
3315
    /// ```
3316
    #[inline]
3317
    pub fn cross(self, other: Self) -> Self {
×
3318
        self.binary_op(other, BinaryOperator::Cross)
×
3319
    }
3320

3321
    /// Calculate the dot product of the current expression by another
3322
    /// expression.
3323
    ///
3324
    /// This is a binary operator, which applies to vector operands of same size
3325
    /// only, and always produces a floating point scalar.
3326
    ///
3327
    /// # Example
3328
    ///
3329
    /// ```
3330
    /// # use bevy_hanabi::*;
3331
    /// # use bevy::math::Vec2;
3332
    /// # let mut w = ExprWriter::new();
3333
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3334
    /// let x = w.lit(Vec2::new(3., -2.));
3335
    ///
3336
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3337
    /// let y = w.lit(Vec2::new(1., 5.));
3338
    ///
3339
    /// // The dot product of both vectors `z = dot(x, y);`.
3340
    /// let z = x.dot(y);
3341
    /// ```
3342
    #[inline]
3343
    pub fn dot(self, other: Self) -> Self {
×
3344
        self.binary_op(other, BinaryOperator::Dot)
×
3345
    }
3346

3347
    /// Calculate the distance between the current expression and another
3348
    /// expression.
3349
    ///
3350
    /// This is a binary operator.
3351
    ///
3352
    /// # Example
3353
    ///
3354
    /// ```
3355
    /// # use bevy_hanabi::*;
3356
    /// # use bevy::math::Vec3;
3357
    /// # let mut w = ExprWriter::new();
3358
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3359
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3360
    ///
3361
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3362
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3363
    ///
3364
    /// // The distance between the vectors `z = distance(x, y);`.
3365
    /// let z = x.distance(y);
3366
    /// ```
3367
    #[inline]
3368
    pub fn distance(self, other: Self) -> Self {
×
3369
        self.binary_op(other, BinaryOperator::Distance)
×
3370
    }
3371

3372
    /// Divide the current expression by another expression.
3373
    ///
3374
    /// This is a binary operator, which applies component-wise to vector
3375
    /// operand expressions.
3376
    ///
3377
    /// You can also use the [`std::ops::Div`] trait directly, via the `/`
3378
    /// symbol, as an alternative to calling this method directly.
3379
    ///
3380
    /// # Example
3381
    ///
3382
    /// ```
3383
    /// # use bevy_hanabi::*;
3384
    /// # use bevy::math::Vec2;
3385
    /// # let mut w = ExprWriter::new();
3386
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3387
    /// let x = w.lit(Vec2::new(3., -2.));
3388
    ///
3389
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3390
    /// let y = w.lit(Vec2::new(1., 5.));
3391
    ///
3392
    /// // The quotient of both vectors `z = x / y;`.
3393
    /// let z = x.div(y); // == vec2<f32>(3., -0.4)
3394
    ///                   // -OR-
3395
    ///                   // let z = x / y;
3396
    /// ```
3397
    #[allow(clippy::should_implement_trait)]
3398
    #[inline]
3399
    pub fn div(self, other: Self) -> Self {
×
3400
        self.binary_op(other, BinaryOperator::Div)
×
3401
    }
3402

3403
    /// Apply the logical operator "greater than or equal" to this expression
3404
    /// and another expression.
3405
    ///
3406
    /// This is a binary operator, which applies component-wise to vector
3407
    /// operand expressions.
3408
    ///
3409
    /// # Example
3410
    ///
3411
    /// ```
3412
    /// # use bevy_hanabi::*;
3413
    /// # use bevy::math::Vec3;
3414
    /// # let mut w = ExprWriter::new();
3415
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3416
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3417
    ///
3418
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3419
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3420
    ///
3421
    /// // The boolean result of the greater than or equal operation `z = (x >= y);`.
3422
    /// let z = x.ge(y); // == vec3<bool>(true, false, true)
3423
    /// ```
3424
    #[inline]
3425
    pub fn ge(self, other: Self) -> Self {
×
3426
        self.binary_op(other, BinaryOperator::GreaterThanOrEqual)
×
3427
    }
3428

3429
    /// Apply the logical operator "greater than" to this expression and another
3430
    /// expression.
3431
    ///
3432
    /// This is a binary operator, which applies component-wise to vector
3433
    /// operand expressions.
3434
    ///
3435
    /// # Example
3436
    ///
3437
    /// ```
3438
    /// # use bevy_hanabi::*;
3439
    /// # use bevy::math::Vec3;
3440
    /// # let mut w = ExprWriter::new();
3441
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3442
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3443
    ///
3444
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3445
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3446
    ///
3447
    /// // The boolean result of the greater than operation `z = (x > y);`.
3448
    /// let z = x.gt(y); // == vec3<bool>(true, false, false)
3449
    /// ```
3450
    #[inline]
3451
    pub fn gt(self, other: Self) -> Self {
×
3452
        self.binary_op(other, BinaryOperator::GreaterThan)
×
3453
    }
3454

3455
    /// Apply the logical operator "less than or equal" to this expression and
3456
    /// another expression.
3457
    ///
3458
    /// This is a binary operator, which applies component-wise to vector
3459
    /// operand expressions.
3460
    ///
3461
    /// # Example
3462
    ///
3463
    /// ```
3464
    /// # use bevy_hanabi::*;
3465
    /// # use bevy::math::Vec3;
3466
    /// # let mut w = ExprWriter::new();
3467
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3468
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3469
    ///
3470
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3471
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3472
    ///
3473
    /// // The boolean result of the less than or equal operation `z = (x <= y);`.
3474
    /// let z = x.le(y); // == vec3<bool>(false, true, true)
3475
    /// ```
3476
    #[inline]
3477
    pub fn le(self, other: Self) -> Self {
×
3478
        self.binary_op(other, BinaryOperator::LessThanOrEqual)
×
3479
    }
3480

3481
    /// Apply the logical operator "less than" to this expression and another
3482
    /// expression.
3483
    ///
3484
    /// This is a binary operator, which applies component-wise to vector
3485
    /// operand expressions.
3486
    ///
3487
    /// # Example
3488
    ///
3489
    /// ```
3490
    /// # use bevy_hanabi::*;
3491
    /// # use bevy::math::Vec3;
3492
    /// # let mut w = ExprWriter::new();
3493
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3494
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3495
    ///
3496
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3497
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3498
    ///
3499
    /// // The boolean result of the less than operation `z = (x < y);`.
3500
    /// let z = x.lt(y); // == vec3<bool>(false, true, false)
3501
    /// ```
3502
    #[inline]
3503
    pub fn lt(self, other: Self) -> Self {
×
3504
        self.binary_op(other, BinaryOperator::LessThan)
×
3505
    }
3506

3507
    /// Take the maximum value of the current expression and another expression.
3508
    ///
3509
    /// This is a binary operator, which applies component-wise to vector
3510
    /// operand expressions.
3511
    ///
3512
    /// # Example
3513
    ///
3514
    /// ```
3515
    /// # use bevy_hanabi::*;
3516
    /// # use bevy::math::Vec2;
3517
    /// # let mut w = ExprWriter::new();
3518
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3519
    /// let x = w.lit(Vec2::new(3., -2.));
3520
    ///
3521
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3522
    /// let y = w.lit(Vec2::new(1., 5.));
3523
    ///
3524
    /// // The maximum of both vectors `z = max(x, y);`.
3525
    /// let z = x.max(y); // == vec2<f32>(3., 5.)
3526
    /// ```
3527
    #[inline]
3528
    pub fn max(self, other: Self) -> Self {
1✔
3529
        self.binary_op(other, BinaryOperator::Max)
4✔
3530
    }
3531

3532
    /// Take the minimum value of the current expression and another expression.
3533
    ///
3534
    /// This is a binary operator, which applies component-wise to vector
3535
    /// operand expressions.
3536
    ///
3537
    /// # Example
3538
    ///
3539
    /// ```
3540
    /// # use bevy_hanabi::*;
3541
    /// # use bevy::math::Vec2;
3542
    /// # let mut w = ExprWriter::new();
3543
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3544
    /// let x = w.lit(Vec2::new(3., -2.));
3545
    ///
3546
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3547
    /// let y = w.lit(Vec2::new(1., 5.));
3548
    ///
3549
    /// // The minimum of both vectors `z = min(x, y);`.
3550
    /// let z = x.min(y); // == vec2<f32>(1., -2.)
3551
    /// ```
3552
    #[inline]
3553
    pub fn min(self, other: Self) -> Self {
1✔
3554
        self.binary_op(other, BinaryOperator::Min)
4✔
3555
    }
3556

3557
    /// Multiply the current expression with another expression.
3558
    ///
3559
    /// This is a binary operator, which applies component-wise to vector
3560
    /// operand expressions.
3561
    ///
3562
    /// You can also use the [`std::ops::Mul`] trait directly, via the `*`
3563
    /// symbol, as an alternative to calling this method directly.
3564
    ///
3565
    /// # Example
3566
    ///
3567
    /// ```
3568
    /// # use bevy_hanabi::*;
3569
    /// # use bevy::math::Vec2;
3570
    /// # let mut w = ExprWriter::new();
3571
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3572
    /// let x = w.lit(Vec2::new(3., -2.));
3573
    ///
3574
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3575
    /// let y = w.lit(Vec2::new(1., 5.));
3576
    ///
3577
    /// // The product of both vectors `z = x * y;`.
3578
    /// let z = x.mul(y); // == vec2<f32>(3., -10.)
3579
    ///                   // -OR-
3580
    ///                   // let z = x * y;
3581
    /// ```
3582
    #[allow(clippy::should_implement_trait)]
3583
    #[inline]
3584
    pub fn mul(self, other: Self) -> Self {
1✔
3585
        self.binary_op(other, BinaryOperator::Mul)
4✔
3586
    }
3587

3588
    /// Calculate the remainder of the division of the current expression by
3589
    /// another expression.
3590
    ///
3591
    /// This is a binary operator.
3592
    ///
3593
    /// # Example
3594
    ///
3595
    /// ```
3596
    /// # use bevy_hanabi::*;
3597
    /// # use bevy::math::Vec3;
3598
    /// # let mut w = ExprWriter::new();
3599
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3600
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3601
    ///
3602
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3603
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3604
    ///
3605
    /// // The remainder of the division `z = x % y;`.
3606
    /// let z = x.rem(y);
3607
    /// ```
3608
    #[allow(clippy::should_implement_trait)]
3609
    #[inline]
3610
    pub fn rem(self, other: Self) -> Self {
×
3611
        self.binary_op(other, BinaryOperator::Remainder)
×
3612
    }
3613

3614
    /// Calculate the step of a value with respect to a reference.
3615
    ///
3616
    /// This is a binary operator, which applies component-wise to vector
3617
    /// operand expressions.
3618
    ///
3619
    /// # Example
3620
    ///
3621
    /// ```
3622
    /// # use bevy_hanabi::*;
3623
    /// # use bevy::math::Vec3;
3624
    /// # let mut w = ExprWriter::new();
3625
    /// // A literal expression `x = vec3<f32>(3., -2.);`.
3626
    /// let x = w.lit(Vec3::new(3., -2., 8.));
3627
    ///
3628
    /// // An edge reference `e = vec3<f32>(1., 5.);`.
3629
    /// let e = w.lit(Vec3::new(1., 5., 8.));
3630
    ///
3631
    /// // The step value
3632
    /// let s = x.step(e); // == vec3<f32>(1., 0., 1.)
3633
    /// ```
3634
    #[allow(clippy::should_implement_trait)]
3635
    #[inline]
3636
    pub fn step(self, edge: Self) -> Self {
×
3637
        // Note: order is step(edge, x) but x.step(edge)
3638
        edge.binary_op(self, BinaryOperator::Step)
×
3639
    }
3640

3641
    /// Subtract another expression from the current expression.
3642
    ///
3643
    /// This is a binary operator, which applies component-wise to vector
3644
    /// operand expressions.
3645
    ///
3646
    /// You can also use the [`std::ops::Sub`] trait directly, via the `-`
3647
    /// symbol, as an alternative to calling this method directly.
3648
    ///
3649
    /// # Example
3650
    ///
3651
    /// ```
3652
    /// # use bevy_hanabi::*;
3653
    /// # use bevy::math::Vec2;
3654
    /// # let mut w = ExprWriter::new();
3655
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3656
    /// let x = w.lit(Vec2::new(3., -2.));
3657
    ///
3658
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3659
    /// let y = w.lit(Vec2::new(1., 5.));
3660
    ///
3661
    /// // The difference of both vectors `z = x - y;`.
3662
    /// let z = x.sub(y); // == vec2<f32>(2., -7.)
3663
    ///                   // -OR-
3664
    ///                   // let z = x - y;
3665
    /// ```
3666
    #[allow(clippy::should_implement_trait)]
3667
    #[inline]
3668
    pub fn sub(self, other: Self) -> Self {
×
3669
        self.binary_op(other, BinaryOperator::Sub)
×
3670
    }
3671

3672
    /// Apply the logical operator "uniform" to this expression and another
3673
    /// expression.
3674
    ///
3675
    /// This is a binary operator, which applies component-wise to vector
3676
    /// operand expressions. That is, for vectors, this produces a vector of
3677
    /// random values where each component is uniformly distributed within the
3678
    /// bounds of the related component of both operands.
3679
    ///
3680
    /// # Example
3681
    ///
3682
    /// ```
3683
    /// # use bevy_hanabi::*;
3684
    /// # use bevy::math::Vec3;
3685
    /// # let mut w = ExprWriter::new();
3686
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3687
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3688
    ///
3689
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3690
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3691
    ///
3692
    /// // A random variable uniformly distributed in [1:3]x[-2:5]x[7:7].
3693
    /// let z = x.uniform(y);
3694
    /// ```
3695
    #[inline]
3696
    pub fn uniform(self, other: Self) -> Self {
×
3697
        self.binary_op(other, BinaryOperator::UniformRand)
×
3698
    }
3699

3700
    /// Apply the logical operator "normal" to this expression and another
3701
    /// expression.
3702
    ///
3703
    /// This is a binary operator, which applies component-wise to vector
3704
    /// operand expressions. That is, for vectors, this produces a vector of
3705
    /// random values where each component is normally distributed with a mean
3706
    /// of the corresponding component of the first operand and a standard
3707
    /// deviation of the corresponding component of the second operand.
3708
    ///
3709
    /// # Example
3710
    ///
3711
    /// ```
3712
    /// # use bevy_hanabi::*;
3713
    /// # use bevy::math::Vec3;
3714
    /// # let mut w = ExprWriter::new();
3715
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3716
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3717
    ///
3718
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3719
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3720
    ///
3721
    /// // A random variable normally distributed in [1:3]x[-2:5]x[7:7].
3722
    /// let z = x.normal(y);
3723
    /// ```
3724
    #[inline]
3725
    pub fn normal(self, other: Self) -> Self {
×
3726
        self.binary_op(other, BinaryOperator::NormalRand)
×
3727
    }
3728

3729
    fn ternary_op(self, second: Self, third: Self, op: TernaryOperator) -> Self {
×
3730
        assert_eq!(self.module, second.module);
×
3731
        assert_eq!(self.module, third.module);
×
3732
        let first = self.expr;
×
3733
        let second = second.expr;
×
3734
        let third = third.expr;
×
3735
        let expr = self.module.borrow_mut().push(Expr::Ternary {
×
3736
            op,
×
3737
            first,
×
3738
            second,
×
3739
            third,
×
3740
        });
3741
        WriterExpr {
3742
            expr,
3743
            module: self.module,
×
3744
        }
3745
    }
3746

3747
    /// Blending linearly ("mix") two expressions with the fraction provided by
3748
    /// a third expression.
3749
    ///
3750
    /// This is a ternary operator, which applies component-wise to vector
3751
    /// operand expressions.
3752
    ///
3753
    /// # Example
3754
    ///
3755
    /// ```
3756
    /// # use bevy_hanabi::*;
3757
    /// # use bevy::math::Vec2;
3758
    /// # let mut w = ExprWriter::new();
3759
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3760
    /// let x = w.lit(Vec2::new(3., -2.));
3761
    ///
3762
    /// // Another literal expression `y = vec2<f32>(1., 4.);`.
3763
    /// let y = w.lit(Vec2::new(1., 4.));
3764
    ///
3765
    /// // A fraction `t = 0.5;`.
3766
    /// let t = w.lit(0.25);
3767
    ///
3768
    /// // The linear blend of x and y via t: z = (1 - t) * x + y * t
3769
    /// let z = x.mix(y, t); // == vec2<f32>(2.5, -0.5)
3770
    /// ```
3771
    #[inline]
3772
    pub fn mix(self, other: Self, fraction: Self) -> Self {
×
3773
        self.ternary_op(other, fraction, TernaryOperator::Mix)
×
3774
    }
3775

3776
    /// Calculate the smooth Hermite interpolation in \[0:1\] of the current
3777
    /// value taken between the given bounds.
3778
    ///
3779
    /// This is a ternary operator, which applies component-wise to vector
3780
    /// operand expressions.
3781
    ///
3782
    /// # Example
3783
    ///
3784
    /// ```
3785
    /// # use bevy_hanabi::*;
3786
    /// # use bevy::math::Vec2;
3787
    /// # let mut w = ExprWriter::new();
3788
    /// // A literal expression `low = vec2<f32>(3., -2.);`.
3789
    /// let low = w.lit(Vec2::new(3., -2.));
3790
    ///
3791
    /// // Another literal expression `high = vec2<f32>(1., 4.);`.
3792
    /// let high = w.lit(Vec2::new(1., 4.));
3793
    ///
3794
    /// // A point `x = vec2<f32>(2., 1.);` between `low` and `high`.
3795
    /// let x = w.lit(Vec2::new(2., 1.));
3796
    ///
3797
    /// // The smooth Hermite interpolation: `t = smoothstep(low, high, x)`
3798
    /// let t = x.smoothstep(low, high); // == 0.5
3799
    /// ```
3800
    #[inline]
3801
    pub fn smoothstep(self, low: Self, high: Self) -> Self {
×
3802
        // Note: order is smoothstep(low, high, x) but x.smoothstep(low, high)
3803
        low.ternary_op(high, self, TernaryOperator::SmoothStep)
×
3804
    }
3805

3806
    /// Construct a `Vec2` from two scalars.
3807
    ///
3808
    /// # Example
3809
    ///
3810
    /// ```
3811
    /// # use bevy_hanabi::*;
3812
    /// # let mut w = ExprWriter::new();
3813
    /// let theta = w.add_property("theta", 0.0.into());
3814
    /// // Convert the angular property `theta` to a 2D vector.
3815
    /// let (cos_theta, sin_theta) = (w.prop(theta).cos(), w.prop(theta).sin());
3816
    /// let circle_pos = cos_theta.vec2(sin_theta);
3817
    /// ```
3818
    #[inline]
3819
    pub fn vec2(self, y: Self) -> Self {
×
3820
        self.binary_op(y, BinaryOperator::Vec2)
×
3821
    }
3822

3823
    /// Construct a `Vec3` from two scalars.
3824
    ///
3825
    /// # Example
3826
    ///
3827
    /// ```
3828
    /// # use bevy_hanabi::*;
3829
    /// # let mut w = ExprWriter::new();
3830
    /// let theta = w.add_property("theta", 0.0.into());
3831
    /// // Convert the angular property `theta` to a 3D vector in a flat plane.
3832
    /// let (cos_theta, sin_theta) = (w.prop(theta).cos(), w.prop(theta).sin());
3833
    /// let circle_pos = cos_theta.vec3(w.lit(0.0), sin_theta);
3834
    /// ```
3835
    #[inline]
3836
    pub fn vec3(self, y: Self, z: Self) -> Self {
×
3837
        self.ternary_op(y, z, TernaryOperator::Vec3)
×
3838
    }
3839

3840
    /// Construct a `Vec4` from a vector XYZ and a scalar W.
3841
    ///
3842
    /// # Example
3843
    ///
3844
    /// ```
3845
    /// # use bevy_hanabi::*;
3846
    /// # let mut w = ExprWriter::new();
3847
    /// let rgb = w.rand(VectorType::VEC3F);
3848
    /// let a = w.lit(1.);
3849
    /// // Build vec4<f32>(R, G, B, A) and convert to 0xAABBGGRR
3850
    /// let col = rgb.vec4_xyz_w(a).pack4x8unorm();
3851
    /// ```
3852
    #[inline]
3853
    pub fn vec4_xyz_w(self, w: Self) -> Self {
×
3854
        self.binary_op(w, BinaryOperator::Vec4XyzW)
×
3855
    }
3856

3857
    /// Cast an expression to a different type.
3858
    ///
3859
    /// # Example
3860
    ///
3861
    /// ```
3862
    /// # use bevy_hanabi::*;
3863
    /// # use bevy::math::Vec2;
3864
    /// # let mut w = ExprWriter::new();
3865
    /// let x = w.lit(Vec2::new(3., -2.));
3866
    /// let y = x.cast(VectorType::VEC3I); // x = vec3<i32>(particle.position);
3867
    /// ```
3868
    pub fn cast(self, target: impl Into<ValueType>) -> Self {
×
3869
        let target = target.into();
×
3870
        let expr = self
×
3871
            .module
×
3872
            .borrow_mut()
3873
            .push(Expr::Cast(CastExpr::new(self.expr, target)));
×
3874
        WriterExpr {
3875
            expr,
3876
            module: self.module,
×
3877
        }
3878
    }
3879

3880
    /// Finalize an expression chain and return the accumulated expression.
3881
    ///
3882
    /// The returned handle indexes the [`Module`] owned by the [`ExprWriter`]
3883
    /// this intermediate expression was built from.
3884
    ///
3885
    /// # Example
3886
    ///
3887
    /// ```
3888
    /// # use bevy_hanabi::*;
3889
    /// # let mut w = ExprWriter::new();
3890
    /// // A literal expression `x = -3.5;`.
3891
    /// let x = w.lit(-3.5);
3892
    ///
3893
    /// // Retrieve the ExprHandle for that expression.
3894
    /// let handle = x.expr();
3895
    /// ```
3896
    #[inline]
3897
    pub fn expr(self) -> ExprHandle {
8✔
3898
        self.expr
8✔
3899
    }
3900
}
3901

3902
impl std::ops::Add<WriterExpr> for WriterExpr {
3903
    type Output = WriterExpr;
3904

3905
    #[inline]
3906
    fn add(self, rhs: WriterExpr) -> Self::Output {
2✔
3907
        self.add(rhs)
6✔
3908
    }
3909
}
3910

3911
impl std::ops::Sub<WriterExpr> for WriterExpr {
3912
    type Output = WriterExpr;
3913

3914
    #[inline]
3915
    fn sub(self, rhs: WriterExpr) -> Self::Output {
×
3916
        self.sub(rhs)
×
3917
    }
3918
}
3919

3920
impl std::ops::Mul<WriterExpr> for WriterExpr {
3921
    type Output = WriterExpr;
3922

3923
    #[inline]
3924
    fn mul(self, rhs: WriterExpr) -> Self::Output {
1✔
3925
        self.mul(rhs)
3✔
3926
    }
3927
}
3928

3929
impl std::ops::Div<WriterExpr> for WriterExpr {
3930
    type Output = WriterExpr;
3931

3932
    #[inline]
3933
    fn div(self, rhs: WriterExpr) -> Self::Output {
×
3934
        self.div(rhs)
×
3935
    }
3936
}
3937

3938
impl std::ops::Rem<WriterExpr> for WriterExpr {
3939
    type Output = WriterExpr;
3940

3941
    #[inline]
3942
    fn rem(self, rhs: WriterExpr) -> Self::Output {
×
3943
        self.rem(rhs)
×
3944
    }
3945
}
3946

3947
#[cfg(test)]
3948
mod tests {
3949
    use bevy::{platform::collections::HashSet, prelude::*};
3950

3951
    use super::*;
3952
    use crate::{MatrixType, ScalarValue, ShaderWriter, VectorType};
3953

3954
    #[test]
3955
    fn module() {
3956
        let mut m = Module::default();
3957

3958
        #[allow(unsafe_code)]
3959
        let unknown = unsafe { ExprHandle::new_unchecked(1) };
3960
        assert!(m.get(unknown).is_none());
3961
        assert!(m.get_mut(unknown).is_none());
3962
        assert!(matches!(
3963
            m.try_get(unknown),
3964
            Err(ExprError::InvalidExprHandleError(_))
3965
        ));
3966
        assert!(matches!(
3967
            m.try_get_mut(unknown),
3968
            Err(ExprError::InvalidExprHandleError(_))
3969
        ));
3970

3971
        let x = m.lit(5.);
3972
        let mut expected = Expr::Literal(LiteralExpr::new(5.));
3973
        assert_eq!(m.get(x), Some(&expected));
3974
        assert_eq!(m.get_mut(x), Some(&mut expected));
3975
        assert_eq!(m.try_get(x), Ok(&expected));
3976
        assert_eq!(m.try_get_mut(x), Ok(&mut expected));
3977
    }
3978

3979
    #[test]
3980
    fn local_var() {
3981
        let property_layout = PropertyLayout::default();
3982
        let particle_layout = ParticleLayout::default();
3983
        let mut ctx =
3984
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3985
        let mut h = HashSet::new();
3986
        for _ in 0..100 {
3987
            let v = ctx.make_local_var();
3988
            assert!(h.insert(v));
3989
        }
3990
    }
3991

3992
    #[test]
3993
    fn make_fn() {
3994
        let property_layout = PropertyLayout::default();
3995
        let particle_layout = ParticleLayout::default();
3996
        let mut ctx =
3997
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3998
        let mut module = Module::default();
3999

4000
        // Make a function
4001
        let func_name = "my_func";
4002
        let args = "arg0: i32, arg1: f32";
4003
        assert!(ctx
4004
            .make_fn(func_name, args, &mut module, &mut |m, ctx| {
4005
                m.lit(3.);
4006
                let v = ctx.make_local_var();
4007
                assert_eq!(v, "var0");
4008
                let code = String::new();
4009
                Ok(code)
4010
            })
4011
            .is_ok());
4012

4013
        // The local function context doesn't influence the outer caller context
4014
        let v = ctx.make_local_var();
4015
        assert_eq!(v, "var0");
4016

4017
        // However the module is common to the outer caller and the function
4018
        assert!(!module.expressions.is_empty());
4019
    }
4020

4021
    #[test]
4022
    fn property() {
4023
        let mut m = Module::default();
4024

4025
        let _my_prop = m.add_property("my_prop", Value::Scalar(345_u32.into()));
4026
        let _other_prop = m.add_property(
4027
            "other_prop",
4028
            Value::Vector(Vec3::new(3., -7.5, 42.42).into()),
4029
        );
4030

4031
        assert!(m.properties().iter().any(|p| p.name() == "my_prop"));
4032
        assert!(m.properties().iter().any(|p| p.name() == "other_prop"));
4033
        assert!(!m.properties().iter().any(|p| p.name() == "do_not_exist"));
4034
    }
4035

4036
    #[test]
4037
    fn writer() {
4038
        // Get a module and its writer
4039
        let w = ExprWriter::new();
4040
        let my_prop = w.add_property("my_prop", 3.0.into());
4041

4042
        // Build some expression
4043
        let x = w.lit(3.).abs().max(w.attr(Attribute::POSITION) * w.lit(2.))
4044
            + w.lit(-4.).min(w.prop(my_prop));
4045
        let x = x.expr();
4046

4047
        // Create an evaluation context
4048
        let property_layout =
4049
            PropertyLayout::new(&[Property::new("my_prop", ScalarValue::Float(3.))]);
4050
        let particle_layout = ParticleLayout::default();
4051
        let m = w.finish();
4052
        let mut context =
4053
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4054

4055
        // Evaluate the expression
4056
        let x = m.try_get(x).unwrap();
4057
        let s = x.eval(&m, &mut context).unwrap();
4058
        assert_eq!(
4059
            "(max(abs(3.), (particle.position) * (2.))) + (min(-4., properties.my_prop))"
4060
                .to_string(),
4061
            s
4062
        );
4063
    }
4064

4065
    #[test]
4066
    fn type_error() {
4067
        let l = Value::Scalar(3.5_f32.into());
4068
        let r: Result<Vec2, ExprError> = l.try_into();
4069
        assert!(r.is_err());
4070
        assert!(matches!(r, Err(ExprError::TypeError(_))));
4071
    }
4072

4073
    #[test]
4074
    fn math_expr() {
4075
        let mut m = Module::default();
4076

4077
        let x = m.attr(Attribute::POSITION);
4078
        let y = m.lit(Vec3::ONE);
4079

4080
        let add = m.add(x, y);
4081
        let sub = m.sub(x, y);
4082
        let mul = m.mul(x, y);
4083
        let div = m.div(x, y);
4084
        let rem = m.rem(x, y);
4085
        let lt = m.lt(x, y);
4086
        let le = m.le(x, y);
4087
        let gt = m.gt(x, y);
4088
        let ge = m.ge(x, y);
4089

4090
        let property_layout = PropertyLayout::default();
4091
        let particle_layout = ParticleLayout::default();
4092
        let mut ctx =
4093
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4094

4095
        for (expr, op) in [
4096
            (add, "+"),
4097
            (sub, "-"),
4098
            (mul, "*"),
4099
            (div, "/"),
4100
            (rem, "%"),
4101
            (lt, "<"),
4102
            (le, "<="),
4103
            (gt, ">"),
4104
            (ge, ">="),
4105
        ] {
4106
            let expr = ctx.eval(&m, expr);
4107
            assert!(expr.is_ok());
4108
            let expr = expr.unwrap();
4109
            assert_eq!(
4110
                expr,
4111
                format!(
4112
                    "(particle.{}) {} (vec3<f32>(1.,1.,1.))",
4113
                    Attribute::POSITION.name(),
4114
                    op,
4115
                )
4116
            );
4117
        }
4118
    }
4119

4120
    #[test]
4121
    fn builtin_expr() {
4122
        let mut m = Module::default();
4123

4124
        // Simulation parameters
4125
        for op in [
4126
            BuiltInOperator::Time,
4127
            BuiltInOperator::DeltaTime,
4128
            BuiltInOperator::VirtualTime,
4129
            BuiltInOperator::VirtualDeltaTime,
4130
            BuiltInOperator::RealTime,
4131
            BuiltInOperator::RealDeltaTime,
4132
        ] {
4133
            let value = m.builtin(op);
4134

4135
            let property_layout = PropertyLayout::default();
4136
            let particle_layout = ParticleLayout::default();
4137
            let mut ctx =
4138
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4139

4140
            let expr = ctx.eval(&m, value);
4141
            assert!(expr.is_ok());
4142
            let expr = expr.unwrap();
4143
            assert_eq!(expr, format!("sim_params.{}", op.name()));
4144
        }
4145

4146
        // is_alive
4147
        {
4148
            let value = m.builtin(BuiltInOperator::IsAlive);
4149

4150
            let property_layout = PropertyLayout::default();
4151
            let particle_layout = ParticleLayout::default();
4152
            let mut ctx =
4153
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4154

4155
            let expr = ctx.eval(&m, value);
4156
            assert!(expr.is_ok());
4157
            let expr = expr.unwrap();
4158
            assert_eq!(expr, "is_alive");
4159
        }
4160

4161
        // BuiltInOperator::Rand (which has side effect)
4162
        for (scalar_type, prefix) in [
4163
            (ScalarType::Bool, "b"),
4164
            (ScalarType::Float, "f"),
4165
            (ScalarType::Int, "i"),
4166
            (ScalarType::Uint, "u"),
4167
        ] {
4168
            let value = m.builtin(BuiltInOperator::Rand(scalar_type.into()));
4169

4170
            // Scalar form
4171
            {
4172
                let property_layout = PropertyLayout::default();
4173
                let particle_layout = ParticleLayout::default();
4174
                let mut ctx =
4175
                    ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4176

4177
                let expr = ctx.eval(&m, value);
4178
                assert!(expr.is_ok());
4179
                let expr = expr.unwrap();
4180
                assert_eq!(expr, "var0");
4181
                assert_eq!(ctx.main_code, format!("let var0 = {}rand();\n", prefix));
4182
            }
4183

4184
            // Vector form
4185
            for count in 2..=4 {
4186
                let vec = m.builtin(BuiltInOperator::Rand(
4187
                    VectorType::new(scalar_type, count).into(),
4188
                ));
4189

4190
                let property_layout = PropertyLayout::default();
4191
                let particle_layout = ParticleLayout::default();
4192
                let mut ctx =
4193
                    ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4194

4195
                let expr = ctx.eval(&m, vec);
4196
                assert!(expr.is_ok());
4197
                let expr = expr.unwrap();
4198
                assert_eq!(expr, "var0");
4199
                assert_eq!(
4200
                    ctx.main_code,
4201
                    format!("let var0 = {}rand{}();\n", prefix, count)
4202
                );
4203
            }
4204
        }
4205
    }
4206

4207
    #[test]
4208
    fn unary_expr() {
4209
        let mut m = Module::default();
4210

4211
        let x = m.attr(Attribute::POSITION);
4212
        let y = m.lit(Vec3::new(1., -3.1, 6.99));
4213
        let z = m.lit(BVec3::new(false, true, false));
4214
        let w = m.lit(Vec4::W);
4215
        let v = m.lit(Vec4::new(-1., 1., 0., 7.2));
4216
        let us = m.lit(0x0u32);
4217
        let uu = m.lit(0x0u32);
4218

4219
        let abs = m.abs(x);
4220
        let acos = m.acos(w);
4221
        let all = m.all(z);
4222
        let any = m.any(z);
4223
        let asin = m.asin(w);
4224
        let atan = m.atan(w);
4225
        let ceil = m.ceil(y);
4226
        let cos = m.cos(y);
4227
        let exp = m.exp(y);
4228
        let exp2 = m.exp2(y);
4229
        let floor = m.floor(y);
4230
        let fract = m.fract(y);
4231
        let inv_sqrt = m.inverse_sqrt(y);
4232
        let length = m.length(y);
4233
        let log = m.log(y);
4234
        let log2 = m.log2(y);
4235
        let norm = m.normalize(y);
4236
        let pack4x8snorm = m.pack4x8snorm(v);
4237
        let pack4x8unorm = m.pack4x8unorm(v);
4238
        let round = m.round(y);
4239
        let saturate = m.saturate(y);
4240
        let sign = m.sign(y);
4241
        let sin = m.sin(y);
4242
        let sqrt = m.sqrt(y);
4243
        let tan = m.tan(y);
4244
        let unpack4x8snorm = m.unpack4x8snorm(us);
4245
        let unpack4x8unorm = m.unpack4x8unorm(uu);
4246
        let comp_x = m.x(w);
4247
        let comp_y = m.y(w);
4248
        let comp_z = m.z(w);
4249
        let comp_w = m.w(w);
4250

4251
        let property_layout = PropertyLayout::default();
4252
        let particle_layout = ParticleLayout::default();
4253
        let mut ctx =
4254
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4255

4256
        for (expr, op, inner) in [
4257
            (
4258
                abs,
4259
                "abs",
4260
                &format!("particle.{}", Attribute::POSITION.name())[..],
4261
            ),
4262
            (acos, "acos", "vec4<f32>(0.,0.,0.,1.)"),
4263
            (all, "all", "vec3<bool>(false,true,false)"),
4264
            (any, "any", "vec3<bool>(false,true,false)"),
4265
            (asin, "asin", "vec4<f32>(0.,0.,0.,1.)"),
4266
            (atan, "atan", "vec4<f32>(0.,0.,0.,1.)"),
4267
            (ceil, "ceil", "vec3<f32>(1.,-3.1,6.99)"),
4268
            (cos, "cos", "vec3<f32>(1.,-3.1,6.99)"),
4269
            (exp, "exp", "vec3<f32>(1.,-3.1,6.99)"),
4270
            (exp2, "exp2", "vec3<f32>(1.,-3.1,6.99)"),
4271
            (floor, "floor", "vec3<f32>(1.,-3.1,6.99)"),
4272
            (fract, "fract", "vec3<f32>(1.,-3.1,6.99)"),
4273
            (inv_sqrt, "inverseSqrt", "vec3<f32>(1.,-3.1,6.99)"),
4274
            (length, "length", "vec3<f32>(1.,-3.1,6.99)"),
4275
            (log, "log", "vec3<f32>(1.,-3.1,6.99)"),
4276
            (log2, "log2", "vec3<f32>(1.,-3.1,6.99)"),
4277
            (norm, "normalize", "vec3<f32>(1.,-3.1,6.99)"),
4278
            (pack4x8snorm, "pack4x8snorm", "vec4<f32>(-1.,1.,0.,7.2)"),
4279
            (pack4x8unorm, "pack4x8unorm", "vec4<f32>(-1.,1.,0.,7.2)"),
4280
            (round, "round", "vec3<f32>(1.,-3.1,6.99)"),
4281
            (saturate, "saturate", "vec3<f32>(1.,-3.1,6.99)"),
4282
            (sign, "sign", "vec3<f32>(1.,-3.1,6.99)"),
4283
            (sin, "sin", "vec3<f32>(1.,-3.1,6.99)"),
4284
            (sqrt, "sqrt", "vec3<f32>(1.,-3.1,6.99)"),
4285
            (tan, "tan", "vec3<f32>(1.,-3.1,6.99)"),
4286
            (unpack4x8snorm, "unpack4x8snorm", "0u"),
4287
            (unpack4x8unorm, "unpack4x8unorm", "0u"),
4288
        ] {
4289
            let expr = ctx.eval(&m, expr);
4290
            assert!(expr.is_ok());
4291
            let expr = expr.unwrap();
4292
            assert_eq!(expr, format!("{}({})", op, inner));
4293
        }
4294

4295
        for (expr, op, inner) in [
4296
            (comp_x, "x", "vec4<f32>(0.,0.,0.,1.)"),
4297
            (comp_y, "y", "vec4<f32>(0.,0.,0.,1.)"),
4298
            (comp_z, "z", "vec4<f32>(0.,0.,0.,1.)"),
4299
            (comp_w, "w", "vec4<f32>(0.,0.,0.,1.)"),
4300
        ] {
4301
            let expr = ctx.eval(&m, expr);
4302
            assert!(expr.is_ok());
4303
            let expr = expr.unwrap();
4304
            assert_eq!(expr, format!("{}.{}", inner, op));
4305
        }
4306
    }
4307

4308
    #[test]
4309
    fn binary_expr() {
4310
        let mut m = Module::default();
4311

4312
        let x = m.attr(Attribute::POSITION);
4313
        let y = m.lit(Vec3::ONE);
4314

4315
        let atan2 = m.atan2(x, y);
4316
        let cross = m.cross(x, y);
4317
        let dist = m.distance(x, y);
4318
        let dot = m.dot(x, y);
4319
        let min = m.min(x, y);
4320
        let max = m.max(x, y);
4321
        let step = m.step(x, y);
4322

4323
        let property_layout = PropertyLayout::default();
4324
        let particle_layout = ParticleLayout::default();
4325
        let mut ctx =
4326
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4327

4328
        for (expr, op) in [
4329
            (atan2, "atan2"),
4330
            (cross, "cross"),
4331
            (dist, "distance"),
4332
            (dot, "dot"),
4333
            (min, "min"),
4334
            (max, "max"),
4335
            (step, "step"),
4336
        ] {
4337
            let expr = ctx.eval(&m, expr);
4338
            assert!(expr.is_ok());
4339
            let expr = expr.unwrap();
4340
            assert_eq!(
4341
                expr,
4342
                format!(
4343
                    "{}(particle.{}, vec3<f32>(1.,1.,1.))",
4344
                    op,
4345
                    Attribute::POSITION.name(),
4346
                )
4347
            );
4348
        }
4349
    }
4350

4351
    #[test]
4352
    fn ternary_expr() {
4353
        let mut m = Module::default();
4354

4355
        let x = m.attr(Attribute::POSITION);
4356
        let y = m.lit(Vec3::ONE);
4357
        let t = m.lit(0.3);
4358

4359
        let mix = m.mix(x, y, t);
4360
        let smoothstep = m.smoothstep(x, y, x);
4361

4362
        let property_layout = PropertyLayout::default();
4363
        let particle_layout = ParticleLayout::default();
4364
        let mut ctx =
4365
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4366

4367
        for (expr, op, third) in [(mix, "mix", t), (smoothstep, "smoothstep", x)] {
4368
            let expr = ctx.eval(&m, expr);
4369
            assert!(expr.is_ok());
4370
            let expr = expr.unwrap();
4371
            let third = ctx.eval(&m, third).unwrap();
4372
            assert_eq!(
4373
                expr,
4374
                format!(
4375
                    "{}(particle.{}, vec3<f32>(1.,1.,1.), {})",
4376
                    op,
4377
                    Attribute::POSITION.name(),
4378
                    third
4379
                )
4380
            );
4381
        }
4382
    }
4383

4384
    #[test]
4385
    fn cast_expr() {
4386
        let mut m = Module::default();
4387

4388
        let x = m.attr(Attribute::POSITION);
4389
        let y = m.lit(IVec2::ONE);
4390
        let z = m.lit(0.3);
4391
        let w = m.lit(false);
4392

4393
        let cx = m.cast(x, VectorType::VEC3I);
4394
        let cy = m.cast(y, VectorType::VEC2U);
4395
        let cz = m.cast(z, ScalarType::Int);
4396
        let cw = m.cast(w, ScalarType::Uint);
4397

4398
        let property_layout = PropertyLayout::default();
4399
        let particle_layout = ParticleLayout::default();
4400
        let mut ctx =
4401
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4402

4403
        for (expr, cast, target) in [
4404
            (x, cx, ValueType::Vector(VectorType::VEC3I)),
4405
            (y, cy, VectorType::VEC2U.into()),
4406
            (z, cz, ScalarType::Int.into()),
4407
            (w, cw, ScalarType::Uint.into()),
4408
        ] {
4409
            let expr = ctx.eval(&m, expr);
4410
            assert!(expr.is_ok());
4411
            let expr = expr.unwrap();
4412
            let cast = ctx.eval(&m, cast);
4413
            assert!(cast.is_ok());
4414
            let cast = cast.unwrap();
4415
            assert_eq!(cast, format!("{}({})", target.to_wgsl_string(), expr));
4416
        }
4417
    }
4418

4419
    #[test]
4420
    fn attribute_pointer() {
4421
        let mut m = Module::default();
4422
        let x = m.attr(Attribute::POSITION);
4423

4424
        let property_layout = PropertyLayout::default();
4425
        let particle_layout = ParticleLayout::default();
4426
        let mut ctx =
4427
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4428

4429
        let res = ctx.eval(&m, x);
4430
        assert!(res.is_ok());
4431
        let xx = res.ok().unwrap();
4432
        assert_eq!(xx, format!("particle.{}", Attribute::POSITION.name()));
4433

4434
        // Use a different context; it's invalid to reuse a mutated context, as the
4435
        // expression cache will have been generated with the wrong context.
4436
        let mut ctx =
4437
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout)
4438
                .with_attribute_pointer();
4439

4440
        let res = ctx.eval(&m, x);
4441
        assert!(res.is_ok());
4442
        let xx = res.ok().unwrap();
4443
        assert_eq!(xx, format!("(*particle).{}", Attribute::POSITION.name()));
4444
    }
4445

4446
    #[test]
4447
    #[should_panic]
4448
    fn invalid_cast_vector_to_scalar() {
4449
        let mut m = Module::default();
4450
        let x = m.lit(Vec2::ONE);
4451
        let _ = m.cast(x, ScalarType::Float);
4452
    }
4453

4454
    #[test]
4455
    #[should_panic]
4456
    fn invalid_cast_matrix_to_scalar() {
4457
        let mut m = Module::default();
4458
        let x = m.lit(Value::Matrix(Mat4::ZERO.into()));
4459
        let _ = m.cast(x, ScalarType::Float);
4460
    }
4461

4462
    #[test]
4463
    #[should_panic]
4464
    fn invalid_cast_matrix_to_vector() {
4465
        let mut m = Module::default();
4466
        let x = m.lit(Value::Matrix(Mat4::ZERO.into()));
4467
        let _ = m.cast(x, VectorType::VEC4F);
4468
    }
4469

4470
    #[test]
4471
    #[should_panic]
4472
    fn invalid_cast_scalar_to_matrix() {
4473
        let mut m = Module::default();
4474
        let x = m.lit(3.);
4475
        let _ = m.cast(x, MatrixType::MAT3X3F);
4476
    }
4477

4478
    #[test]
4479
    #[should_panic]
4480
    fn invalid_cast_vector_to_matrix() {
4481
        let mut m = Module::default();
4482
        let x = m.lit(Vec3::ZERO);
4483
        let _ = m.cast(x, MatrixType::MAT2X4F);
4484
    }
4485

4486
    #[test]
4487
    fn cast_expr_new() {
4488
        let mut m = Module::default();
4489

4490
        let x = m.attr(Attribute::POSITION);
4491
        let c = CastExpr::new(x, VectorType::VEC3F);
4492
        assert_eq!(c.value_type(), ValueType::Vector(VectorType::VEC3F));
4493
        assert_eq!(c.is_valid(&m), Some(true));
4494

4495
        let x = m.attr(Attribute::POSITION);
4496
        let c = CastExpr::new(x, ScalarType::Bool);
4497
        assert_eq!(c.value_type(), ValueType::Scalar(ScalarType::Bool));
4498
        assert_eq!(c.is_valid(&m), Some(false)); // invalid cast vector -> scalar
4499

4500
        let p = m.add_property("my_prop", 3.0.into());
4501
        let y = m.prop(p);
4502
        let c = CastExpr::new(y, MatrixType::MAT2X3F);
4503
        assert_eq!(c.value_type(), ValueType::Matrix(MatrixType::MAT2X3F));
4504
        assert_eq!(c.is_valid(&m), None); // properties' value_type() is unknown
4505
    }
4506

4507
    #[test]
4508
    fn side_effect() {
4509
        let mut m = Module::default();
4510

4511
        // Adding the same cloned expression with side effect to itself should yield
4512
        // twice the value, and not two separate evaluations of the expression.
4513
        // CORRECT:
4514
        //   let r = frand();
4515
        //   r + r
4516
        // INCORRECT:
4517
        //   frand() + frand()
4518

4519
        let r = m.builtin(BuiltInOperator::Rand(ScalarType::Float.into()));
4520
        let r2 = r;
4521
        let r3 = r2;
4522
        let a = m.add(r, r2);
4523
        let b = m.mix(r, r2, r3);
4524
        let c = m.abs(a);
4525

4526
        {
4527
            let property_layout = PropertyLayout::default();
4528
            let particle_layout = ParticleLayout::default();
4529
            let mut ctx =
4530
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4531
            let value = ctx.eval(&m, a).unwrap();
4532
            assert_eq!(value, "(var0) + (var0)");
4533
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4534
        }
4535

4536
        {
4537
            let property_layout = PropertyLayout::default();
4538
            let particle_layout = ParticleLayout::default();
4539
            let mut ctx =
4540
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4541
            let value = ctx.eval(&m, b).unwrap();
4542
            assert_eq!(value, "mix(var0, var0, var0)");
4543
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4544
        }
4545

4546
        {
4547
            let property_layout = PropertyLayout::default();
4548
            let particle_layout = ParticleLayout::default();
4549
            let mut ctx =
4550
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4551
            let value = ctx.eval(&m, c).unwrap();
4552
            assert_eq!(value, "abs((var0) + (var0))");
4553
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4554
        }
4555
    }
4556

4557
    // #[test]
4558
    // fn serde() {
4559
    //     let v = Value::Scalar(3.0_f32.into());
4560
    //     let l: LiteralExpr = v.into();
4561
    //     assert_eq!(Ok(v), l.eval());
4562
    //     let s = ron::to_string(&l).unwrap();
4563
    //     println!("literal: {:?}", s);
4564
    //     let l_serde: LiteralExpr = ron::from_str(&s).unwrap();
4565
    //     assert_eq!(l_serde, l);
4566

4567
    //     let b: ExprHandle = Box::new(l);
4568
    //     let s = ron::to_string(&b).unwrap();
4569
    //     println!("boxed literal: {:?}", s);
4570
    //     let b_serde: ExprHandle = ron::from_str(&s).unwrap();
4571
    //     assert!(b_serde.is_const());
4572
    //     assert_eq!(b_serde.to_wgsl_string(), b.to_wgsl_string());
4573

4574
    //     let v0 = Value::Scalar(3.0_f32.into());
4575
    //     let v1 = Value::Scalar(2.5_f32.into());
4576
    //     let l0: LiteralExpr = v0.into();
4577
    //     let l1: LiteralExpr = v1.into();
4578
    //     let a = l0 + l1;
4579
    //     assert!(a.is_const());
4580
    //     assert_eq!(Ok(Value::Scalar(5.5_f32.into())), a.eval());
4581
    //     let s = ron::to_string(&a).unwrap();
4582
    //     println!("add: {:?}", s);
4583
    //     let a_serde: AddExpr = ron::from_str(&s).unwrap();
4584
    //     println!("a_serde: {:?}", a_serde);
4585
    //     assert_eq!(a_serde.left.to_wgsl_string(), l0.to_wgsl_string());
4586
    //     assert_eq!(a_serde.right.to_wgsl_string(), l1.to_wgsl_string());
4587
    // }
4588
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc